Kanban skill validation, availability, and packaging fixes

NousResearch/hermes-agent · cluster 22921 · agent

Data as of

10 open items. Fix merged in #23273. Check it covers your case.

The short answer

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

These items address bugs and features around skill resolution in the kanban system: validating skill names at creation and dispatch time, excluding archived skills from availability checks, shipping bundled skills in the package, and related swarm-level skill override support.

Open issues6

  • Issue#34273feat(swarm): support custom verifier/synthesizer body + skills
  • Issue#35202bug(kanban): failure_limit circuit breaker bypassed when worker crashes before first heartbeat
  • Issue#44072kanban create: --skill flag should validate against installed skill registry at dispatch time
  • Issue#44675Kanban: worker crashes silently when --skill references non-existent skill in worker profile
  • Issue#54088Kanban worker should not crash when an optional preloaded skill cannot be resolved
  • Issue#59764Two dispatch-contract mismatches: (a) goal_mode tasks reject `kanban_block` with `kind` unset / `capability` / `transient`, but the tool schema documents all four kinds and says "Omit only if none apply"; (b) card `skills` that a worker profile lacks are skipped with only a log-file warning ("Unknown skill(s)"), silently losing the context the card was authored with

Open PRs4

  • PR#35212fix(kanban): count stale-claim reclaims toward circuit breaker
  • PR#44686fix(kanban): surface worker crash cause from log in detect_crashed_workers
  • PR#54100fix(kanban): warn and continue when optional skill is unavailable (#54088)
  • PR#112608feat(swarm): per-swarm verifier + synthesizer body and skills overrides (#34273)

Fixes on record

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

  • #23273 fix(kanban): reject toolset names in task skills field (salvage #22933)

    merged to main

    files: hermes_cli/kanban_db.py, tests/hermes_cli/test_kanban_core_functionality.py, tests/plugins/test_kanban_dashboard_plugin.py, tools/kanban_tools.py

  • #28368 fix(kanban): auto-install bundled skills (e.g. kanban-worker) on kanban init (#23884)

    merged to main

    files: hermes_cli/kanban.py

  • #28421 fix(packaging): ship bundled skills in wheel (#23738)

    merged to main

    files: hermes_constants.py, setup.py, tools/skills_sync.py

    Show the diff
    • hermes_constants.py
      @@ -5,6 +5,7 @@
       """
       
       import os
      +import sysconfig
       from contextvars import ContextVar, Token
       from pathlib import Path
       
      @@ -139,6 +140,23 @@ def get_default_hermes_root() -> Path:
           return env_path
       
       
      +def _get_packaged_data_dir(name: str) -> Path | None:
      +    """Return an installed data-files directory if one exists.
      +
      +    Used to discover bundled skills/optional-skills when Hermes is installed
      +    from a wheel that emitted them via setuptools data_files.
      +    """
      +    candidates = []
      +    for scheme in ("data", "purelib", "platlib"):
      +        raw = sysconfig.get_path(scheme)
      +        if raw:
      +            candidates.append(Path(raw) / name)
      +    for candidate in candidates:
      +        if candidate.exists():
      +            return candidate
      +    return None
      +
      +
       def get_optional_skills_dir(default: Path | None = None) -> Path:
           """Return the optional-skills directory, honoring package-manager wrappers.
       
      @@ -148,11 +166,34 @@ def get_optional_skills_dir(default: Path | None = None) -> Path:
           override = os.getenv("HERMES_OPTIONAL_SKILLS", "").strip()
           if override:
               return Path(override)
      +    packaged = _get_packaged_data_dir("optional-skills")
      +    if packaged is not None:
      +        return packaged
           if default is not None:
               return default
           return get_hermes_home() / "optional-skills"
       
       
      +def get_bundled_skills_dir(default: Path | None = None) -> Path:
      +    """Return the bundled skills directory for source and packaged installs.
      +
      +    Resolution order:
      +        1. ``HERMES_BUNDLED_SKILLS`` env var (Nix wrapper / explicit override)
      +        2. Wheel-installed ``<sysconfig data>/skills`` (pip install path)
      +        3. Caller-supplied ``default`` (typically the source-checkout path)
      +        4. ``<HERMES_HOME>/skills`` last-resort
      +    """
      +    override = os.getenv("HERMES_BUNDLED_SKILLS", "").strip()
      +    if override:
      +        return Path(override)
      +    packaged = _get_packaged_data_dir("skills")
      +    if packaged is not None:
      +        return packaged
      +    if default is not None:
      +        return default
      +    return get_hermes_home() / "skills"
      +
      +
       def get_hermes_dir(new_subpath: str, old_name: str) -> Path:
           """Resolve a Hermes subdirectory with backward compatibility.
       
    • setup.py
      @@ -0,0 +1,28 @@
      +from __future__ import annotations
      +
      +from collections import defaultdict
      +from pathlib import Path
      +
      +from setuptools import setup
      +
      +
      +REPO_ROOT = Path(__file__).parent.resolve()
      +
      +
      +def _data_file_tree(root_name: str) -> list[tuple[str, list[str]]]:
      +    root = REPO_ROOT / root_name
      +    grouped: defaultdict[str, list[str]] = defaultdict(list)
      +    for path in sorted(root.rglob("*")):
      +        if not path.is_file():
      +            continue
      +        rel_path = path.relative_to(REPO_ROOT)
      +        grouped[str(rel_path.parent)].append(str(rel_path))
      +    return sorted(grouped.items())
      +
      +
      +setup(
      +    data_files=[
      +        *_data_file_tree("skills"),
      +        *_data_file_tree("optional-skills"),
      +    ]
      +)
    • tools/skills_sync.py
      @@ -26,7 +26,7 @@
       import os
       import shutil
       from pathlib import Path
      -from hermes_constants import get_hermes_home
      +from hermes_constants import get_bundled_skills_dir, get_hermes_home
       from typing import Dict, List, Tuple
       from utils import atomic_replace
       
      @@ -42,12 +42,10 @@ def _get_bundled_dir() -> Path:
           """Locate the bundled skills/ directory.
       
           Checks HERMES_BUNDLED_SKILLS env var first (set by Nix wrapper),
      -    then falls back to the relative path from this source file.
      +    then a wheel-installed data dir, then falls back to the relative
      +    path from this source file.
           """
      -    env_override = os.getenv("HERMES_BUNDLED_SKILLS")
      -    if env_override:
      -        return Path(env_override)
      -    return Path(__file__).parent.parent / "skills"
      +    return get_bundled_skills_dir(Path(__file__).parent.parent / "skills")
       
       
       def _read_manifest() -> Dict[str, str]:
  • #50473 refactor(kanban): fold worker/orchestrator skills into injected guidance

    merged to main

    files: agent/prompt_builder.py, agent/skill_utils.py, hermes_cli/kanban.py, hermes_cli/kanban_db.py, hermes_cli/kanban_swarm.py, optional-skills/creative/kanban-video-orchestrator/SKILL.md, optional-skills/creative/kanban-video-orchestrator/assets/setup.sh.tmpl, optional-skills/creative/kanban-video-orchestrator/references/examples.md, optional-skills/creative/kanban-video-orchestrator/references/kanban-setup.md, optional-skills/creative/kanban-video-orchestrator/references/role-archetypes.md, optional-skills/creative/kanban-video-orchestrator/references/tool-matrix.md, optional-skills/creative/kanban-video-orchestrator/scripts/bootstrap_pipeline.py, skills/devops/kanban-orchestrator/SKILL.md, skills/devops/kanban-worker/SKILL.md, tests/hermes_cli/test_kanban_core_functionality.py, tests/hermes_cli/test_kanban_goal_mode.py, tests/tools/test_kanban_tools.py, tools/kanban_tools.py, website/docs/reference/skills-catalog.md, website/docs/user-guide/features/kanban-worker-lanes.md (+12 more)

    Show the diff
    • agent/prompt_builder.py
      @@ -238,6 +238,23 @@ def _strip_yaml_frontmatter(content: str) -> str:
           "of the decomposition. Do NOT execute the work yourself; your job is "
           "routing, not implementation.\n"
           "\n"
      +    "## Reference details that change outcomes\n"
      +    "\n"
      +    "- **Workspace.** `cd $HERMES_KANBAN_WORKSPACE` first. For a `worktree` kind "
      +    "with no `.git`, `git worktree add <path> "
      +    "${HERMES_KANBAN_BRANCH:-wt/$HERMES_KANBAN_TASK}` from the main repo, then "
      +    "cd there.\n"
      +    "- **Deliverables.** Files a human wants go in "
      +    "`kanban_complete(artifacts=[<absolute paths>])` (top-level param; paths in "
      +    "`metadata` are NOT uploaded). Files must exist at completion.\n"
      +    "- **Created cards.** List ids in `kanban_complete(created_cards=[...])` "
      +    "ONLY when captured from a successful `kanban_create` return — never invent "
      +    "or paste ids; the kernel rejects the completion on any phantom id.\n"
      +    "- **Orchestrating: discover profiles first.** The dispatcher SILENTLY "
      +    "drops a card with an unknown assignee (it sits in `ready` forever). Ground "
      +    "every assignee in a real profile (`hermes profile list`, or ask the user), "
      +    "and express dependencies via `parents=[...]` on `kanban_create`, not prose.\n"
      +    "\n"
           "## Do NOT\n"
           "\n"
           "- Do not shell out to `hermes kanban <verb>` for board operations. Use "
    • agent/skill_utils.py
      @@ -280,9 +280,9 @@ def skill_matches_environment(frontmatter: Dict[str, Any]) -> bool:
           This is an OFFER-time filter: it controls whether a skill shows up in the
           skills index / autocomplete / slash-command list. It is intentionally NOT
           enforced by ``skill_view`` or ``--skills`` preloading — an explicit load is
      -    explicit consent, and load-bearing force-loads (e.g. the kanban dispatcher
      -    injecting ``--skills kanban-worker``) must always succeed regardless of how
      -    the offer surfaces filter the skill.
      +    explicit consent, and load-bearing force-loads (e.g. a dispatcher pinning
      +    a task to a specialist skill via ``--skills``) must always succeed
      +    regardless of how the offer surfaces filter the skill.
       
           A skill matches when ANY of its declared environments is currently active
           (OR semantics, mirroring ``platforms``). Unknown env tags fail open.
    • hermes_cli/kanban.py
      @@ -26,7 +26,7 @@
       
       from hermes_cli import kanban_db as kb
       from hermes_cli import kanban_swarm as ks
      -from hermes_cli.profiles import get_active_profile_name, get_profile_dir, seed_profile_skills
      +from hermes_cli.profiles import get_active_profile_name
       
       
       # ---------------------------------------------------------------------------
      @@ -330,8 +330,8 @@ def build_parser(parent_subparsers: argparse._SubParsersAction) -> argparse.Argu
                                 help="Author name recorded on the task (default: user)")
           p_create.add_argument("--skill", action="append", default=[], dest="skills",
                                 help="Skill to force-load into the worker "
      -                               "(repeatable). Appended to the built-in "
      -                               "kanban-worker skill. Example: "
      +                               "(repeatable). The kanban lifecycle is already "
      +                               "injected automatically. Example: "
                                      "--skill translation --skill github-code-review")
           p_create.add_argument("--max-retries", type=int, default=None,
                                 metavar="N",
      @@ -1223,21 +1223,6 @@ def _cmd_init(args: argparse.Namespace) -> int:
           path = kb.init_db()
           print(f"Kanban DB initialized at {path}")
       
      -    # Seed bundled skills (e.g. kanban-worker) into the active profile so
      -    # the kanban dispatcher can use them without a separate `hermes profile
      -    # create` step.  This is best-effort — a missing or broken profile is
      -    # not fatal to `kanban init`.
      -    try:
      -        profile_name = get_active_profile_name() or "default"
      -        profile_dir = get_profile_dir(profile_name)
      -        result = seed_profile_skills(profile_dir, quiet=True)
      -        if result:
      -            copied = result.get("copied", [])
      -            if copied:
      -                print(f"Seeded skill(s) into profile {profile_name}: {', '.join(copied)}")
      -    except Exception:
      -        pass  # best-effort
      -
           print()
           # Enumerate profiles on disk so the user knows what assignees are
           # already addressable. Multica does this auto-detection on its
      @@ -1461,8 +1446,7 @@ def _cmd_show(args: argparse.Namespace) -> int:
               parents = kb.parent_ids(conn, args.task_id)
               children = kb.child_ids(conn, args.task_id)
               runs = kb.list_runs(conn, args.task_id, **rsk)
      -        # Workers hand off via ``task_runs.summary`` (kanban-worker skill);
      -        # ``tasks.result`` is left NULL unless the caller explicitly passed
      +        # Workers hand off via ``task_runs.summary``; ``tasks.result`` is left NULL unless the caller explicitly passed
               # ``result=``. Surfacing the latest summary here keeps ``show`` from
               # looking like a no-op when the worker actually did real work.
               latest_summary = kb.latest_summary(conn, args.task_id)
    • hermes_cli/kanban_db.py
      @@ -804,10 +804,9 @@ class Task:
           current_run_id: Optional[int] = None
           workflow_template_id: Optional[str] = None
           current_step_key: Optional[str] = None
      -    # Force-loaded skills for the worker on this task (appended to the
      -    # dispatcher's built-in `kanban-worker` via --skills). Stored as a
      -    # JSON array of skill names. None = use only the defaults; empty
      -    # list = explicitly no extra skills.
      +    # Force-loaded skills for the worker on this task (passed via
      +    # --skills). Stored as a JSON array of skill names. None = use only
      +    # the defaults; empty list = explicitly no extra skills.
           skills: Optional[list] = None
           model_override: Optional[str] = None
           # Per-task override for the consecutive-failure circuit breaker.
      @@ -1045,8 +1044,7 @@ class Event:
           workflow_template_id TEXT,
           current_step_key     TEXT,
           -- Force-loaded skills for the worker on this task, stored as JSON.
      -    -- Appended to the dispatcher's built-in `--skills kanban-worker`.
      -    -- NULL or empty array = no extras.
      +    -- Passed to the worker via `--skills`. NULL or empty array = no extras.
           skills               TEXT,
           -- Per-task model override. When set, the dispatcher passes -m <model>
           -- to the worker, overriding the profile's default model. NULL = use
      @@ -1848,8 +1846,7 @@ def _migrate_add_optional_columns(conn: sqlite3.Connection) -> None:
               )
           if "skills" not in cols:
               # JSON array of skill names the dispatcher force-loads into the
      -        # worker (additive to the built-in `kanban-worker`). NULL is fine
      -        # for existing rows.
      +        # worker via --skills. NULL is fine for existing rows.
               _add_column_if_missing(conn, "tasks", "skills", "skills TEXT")
       
           if "max_retries" not in cols:
      @@ -2285,9 +2282,8 @@ def create_task(
       
           ``skills`` is an optional list of skill names to force-load into
           the worker when dispatched. Stored as JSON; the dispatcher passes
      -    each name to ``hermes --skills ...`` alongside the built-in
      -    ``kanban-worker``. Use this to pin a task to a specialist skill
      -    (e.g. ``skills=["translation"]`` so the worker loads the
      +    each name to ``hermes --skills ...``. Use this to pin a task to a
      +    specialist skill (e.g. ``skills=["translation"]`` so the worker loads the
           translation skill regardless of the profile's default config).
           """
           assignee = _canonical_assignee(assignee)
      @@ -2348,7 +2344,7 @@ def create_task(
                       f"{quoted} {noun}, not skill name(s). "
                       "Put toolsets in the assignee profile's `toolsets:` config "
                       "instead of per-task skills. Skills are named skill bundles "
      -                "(e.g. `kanban-worker`, `blogwatcher`); toolsets are runtime "
      +                "(e.g. `blogwatcher`, `github-code-review`); toolsets are runtime "
                       "capabilities (e.g. `web`, `browser`, `terminal`)."
                   )
               skills_list = cleaned
      @@ -6994,11 +6990,11 @@ def _dispatch_once_locked(
               if claimed.workspace_kind == "worktree":
                   set_branch_name(conn, claimed.id, resolved_branch_name or (claimed.branch_name or "").strip() or f"wt/{claimed.id}")
               _maybe_emit_scratch_tip(conn, claimed.id, claimed.workspace_kind)
      -        # Force-load sdlc-review skill for review agents.  The
      -        # _default_spawn function already auto-loads kanban-worker, and
      -        # appends task.skills via --skills.  Setting task.skills here
      -        # means the review agent gets both kanban-worker (lifecycle)
      -        # and sdlc-review (review logic: AC verification, merge, etc.).
      +        # Force-load the sdlc-review skill for review agents — it carries
      +        # the review logic (AC verification, merge, etc.). The mandatory
      +        # kanban lifecycle is already injected into every worker's system
      +        # prompt via KANBAN_GUIDANCE, so this is the only extra skill the
      +        # review agent needs.
               claimed.skills = ["sdlc-review"]
               _spawn = spawn_fn if spawn_fn is not None else _default_spawn
               try:
      @@ -7223,41 +7219,6 @@ def _resolve_hermes_argv() -> list[str]:
           return _module_hermes_argv()
       
       
      -def _kanban_worker_skill_available(hermes_home: Optional[str]) -> bool:
      -    """True if the bundled ``kanban-worker`` skill resolves for the home the
      -    spawned worker will run under.
      -
      -    The dispatcher injects ``--skills kanban-worker`` into every worker. When
      -    the worker activates a profile (``hermes -p <name>``), its ``SKILLS_DIR``
      -    becomes ``<profile_home>/skills`` — which on many profiles does NOT contain
      -    the bundled skill (it ships in the *default* root home, not every
      -    profile-scoped skills dir). Preloading a missing skill is fatal at CLI
      -    startup (``ValueError: Unknown skill(s): kanban-worker``), aborting the
      -    worker before the agent loop runs. Gate the flag on actual resolvability;
      -    the kanban lifecycle contract is still injected via ``KANBAN_GUIDANCE``, so
      -    omitting the flag only drops the supplementary pattern library.
      -    """
      -    from pathlib import Path as _Path
      -
      -    # An unset HERMES_HOME means the worker falls back to the default root
      -    # home (``~/.hermes``), which ships the bundled skill.
      -    base = _Path(hermes_home) if hermes_home else (_Path.home() / ".hermes")
      -    skills_root = base / "skills"
      -    if not skills_root.is_dir():
      -        return False
      -    # Canonical bundled location first (cheap), then a bounded scan for
      -    # profiles that have it nested elsewhere.
      -    if (skills_root / "devops" / "kanban-worker" / "SKILL.md").is_file():
      -        return True
      -    try:
      -        for skill_md in skills_root.rglob("kanban-worker/SKILL.md"):
      -            if skill_md.is_file():
      -                return True
      -    except OSError:
      -        pass
      -    return False
      -
      -
       def _worker_terminal_timeout_env(
           max_runtime_seconds: Optional[int],
           current_timeout: Optional[str],
      @@ -7440,32 +7401,14 @@ def _default_spawn(
               # profile-local worker sessions still register configured hooks.
               "--accept-hooks",
           ]
      -    # Auto-load the kanban-worker skill so every dispatched worker
      -    # has the pattern library (good summary/metadata shapes, retry
      -    # diagnostics, block-reason examples) in its context, even if
      -    # the profile hasn't wired it into skills config. The MANDATORY
      -    # lifecycle is already in the system prompt via KANBAN_GUIDANCE;
      -    # this skill is the deeper reference. Users can point a profile
      -    # at a different/additional skill via config if they want —
      -    # --skills is additive to the profile's default skill set.
      -    #
      -    # Only add the flag when the skill actually resolves for the home
      -    # the worker runs under: the bundled skill is absent from many
      -    # profile-scoped skills dirs, and preloading a missing skill is
      -    # fatal at CLI startup. Omitting it is safe — the lifecycle
      -    # contract still ships via KANBAN_GUIDANCE.
      -    if _kanban_worker_skill_available(env.get("HERMES_HOME")):
      -        cmd.extend(["--skills", "kanban-worker"])
           # Per-task force-loaded skills. Each name goes in its own
           # `--skills X` pair rather than a single comma-joined arg: the CLI
           # accepts both forms (action='append' + comma-split), but
           # per-name pairs are easier to read in `ps` output and avoid any
           # quoting ambiguity if a skill name ever contains unusual chars.
      -    # Dedupe against the built-in so we don't double-load kanban-worker
      -    # if a task author asks for it explicitly.
           if task.skills:
               for sk in task.skills:
      -            if sk and sk != "kanban-worker":
      +            if sk:
                       cmd.extend(["--skills", sk])
           if task.model_override:
               cmd.extend(["-m", task.model_override])
      @@ -8322,7 +8265,7 @@ def latest_run(conn: sqlite3.Connection, task_id: str) -> Optional[Run]:
       def latest_summary(conn: sqlite3.Connection, task_id: str) -> Optional[str]:
           """Return the latest non-null ``task_runs.summary`` for ``task_id``.
       
      -    The kanban-worker skill writes its handoff to ``task_runs.summary``
      +    The worker writes its handoff to ``task_runs.summary``
           via ``complete_task(summary=...)``; ``tasks.result`` is left empty
           unless the caller passes ``result=`` explicitly. Dashboards and CLI
           "show" views need this value to surface what a worker actually did
    • hermes_cli/kanban_swarm.py
      @@ -124,7 +124,6 @@ def create_swarm(
               idempotency_key=idempotency_key,
               workspace_kind=workspace_kind,
               workspace_path=workspace_path,
      -        skills=["kanban-orchestrator"],
           )
       
           # If idempotency returned an existing non-archived root, do not duplicate the
    • optional-skills/creative/kanban-video-orchestrator/SKILL.md
      @@ -8,7 +8,7 @@ platforms: [linux, macos, windows]
       metadata:
         hermes:
           tags: [video, kanban, multi-agent, orchestration, production-pipeline]
      -    related_skills: [kanban-orchestrator, kanban-worker, ascii-video, manim-video, p5js, comfyui, touchdesigner-mcp, blender-mcp, pixel-art, ascii-art, songwriting-and-ai-music, heartmula, songsee, spotify, youtube-content, claude-design, excalidraw, architecture-diagram, concept-diagrams, baoyu-comic, baoyu-infographic, humanizer, gif-search, meme-generation]
      +    related_skills: [ascii-video, manim-video, p5js, comfyui, touchdesigner-mcp, blender-mcp, pixel-art, ascii-art, songwriting-and-ai-music, heartmula, songsee, spotify, youtube-content, claude-design, excalidraw, architecture-diagram, concept-diagrams, baoyu-comic, baoyu-infographic, humanizer, gif-search, meme-generation]
           credits: |
             The single-project workspace layout, profile-config patching pattern,
             SOUL.md-per-profile model, TEAM.md task-graph convention, and
      @@ -174,8 +174,9 @@ task graphs. See **[references/examples.md](references/examples.md)**.
       6. **The director never executes.** Even with the full `kanban + terminal +
          file` toolset, the director's `SOUL.md` rules forbid it from executing
          work itself. It decomposes and routes only — every concrete task becomes
      -   a `hermes kanban create` call to a specialist profile. The
      -   `kanban-orchestrator` skill spells this out further.
      +   a `hermes kanban create` call to a specialist profile. The kanban
      +   orchestration guidance auto-injected into every kanban worker's system
      +   prompt spells this out further.
       
       7. **Don't over-decompose.** A 30-second product video does NOT need 20 tasks.
          Aim for the smallest task graph that still parallelizes well and exposes the
    • optional-skills/creative/kanban-video-orchestrator/assets/setup.sh.tmpl
      @@ -64,7 +64,7 @@ echo "═══ Configuring profiles ═══"
       configure_profile() {
           local profile="$1"
           local toolsets_json="$2"     # JSON array string, e.g. '["kanban","terminal","file"]'
      -    local skills_json="$3"       # JSON array string, e.g. '["kanban-worker","ascii-video"]'
      +    local skills_json="$3"       # JSON array string, e.g. '["ascii-video"]'
           python3 - "$profile" "$toolsets_json" "$skills_json" "$WORKSPACE" <<'PY'
       """Patch a Hermes profile config.yaml using PyYAML so we don't depend on the
       exact default-config string format. Validates the patch took effect and exits
    • optional-skills/creative/kanban-video-orchestrator/references/examples.md
      @@ -39,8 +39,8 @@ T8  reviewer         final QA                                 (parent: T7)
       **Key choices:**
       - Local ComfyUI via `comfyui` skill is preferred over external API for
         cost/control — but external APIs are fine if ComfyUI isn't installed
      -- `editor` profile is ffmpeg-only, no Hermes skill required beyond
      -  `kanban-worker`
      +- `editor` profile is ffmpeg-only, no Hermes skill required (kanban guidance
      +  is auto-injected into every kanban worker)
       - Storyboarder produces `storyboard.excalidraw` alongside the markdown
       
       ## Example 2 — Product / marketing teaser
    • optional-skills/creative/kanban-video-orchestrator/references/kanban-setup.md
      @@ -101,7 +101,7 @@ default-config schema drift:
       configure_profile() {
           local profile="$1"
           local toolsets_json="$2"     # JSON array, e.g. '["kanban","terminal","file"]'
      -    local skills_json="$3"       # JSON array, e.g. '["kanban-worker","ascii-video"]'
      +    local skills_json="$3"       # JSON array, e.g. '["ascii-video"]'
           python3 - "$profile" "$toolsets_json" "$skills_json" <<'PY'
       import json, os, sys, yaml
       profile, ts_json, sk_json = sys.argv[1:4]
      @@ -133,16 +133,16 @@ the entire production. **Critical content for the director's SOUL.md:**
       
       - **Anti-temptation rules:** "Do not execute the work yourself. For every
         concrete task, create a kanban task and assign it. Decompose, route, comment,
      -  approve — that's the whole job." (The `kanban-orchestrator` skill provides
      -  the deeper playbook; load it.)
      +  approve — that's the whole job." (The kanban orchestration guidance is
      +  auto-injected into every kanban worker's system prompt — no skill to load.)
       - **Decomposition steps:** Read `brief.md`, `TEAM.md`, `taste/`. Use the team
         graph in `TEAM.md` to fan out tasks.
       - **The workspace_path rule** (see below).
       
       Other profiles' SOUL.md is briefer; mostly mechanical: who you are, what you
       read, what you produce, what skills/tools to use, where to write outputs.
      -Most non-director profiles should `always_load: kanban-worker` for the
      -deeper-than-baseline kanban guidance.
      +The kanban lifecycle guidance is auto-injected into every kanban worker's
      +system prompt, so no profile needs to load a kanban skill.
       
       ### Initial kanban task
       
    • optional-skills/creative/kanban-video-orchestrator/references/role-archetypes.md
      @@ -18,15 +18,16 @@ The vision-holder. Reads the brief and brand guide, decomposes into a task
       graph, comments to steer creative direction, approves the final cut.
       
       - **Toolsets:** kanban, terminal, file
      -- **Skills:** `kanban-orchestrator`. The kanban plugin auto-injects baseline
      -  orchestration guidance for free; `kanban-orchestrator` is the deeper
      -  decomposition playbook. Add `creative-ideation` if the brief is wide-open
      -  and needs framing help.
      +- **Skills:** no extra skill needed — the kanban orchestration guidance
      +  (decomposition playbook, "decompose, don't execute" discipline) is
      +  auto-injected into every kanban worker's system prompt. Add
      +  `creative-ideation` if the brief is wide-open and needs framing help.
       - **Personality:** Tied to the brand voice — see `assets/soul.md.tmpl`
       
       The director has the same toolset as everyone else, but its `SOUL.md` rules
       **forbid** execution. The "decompose, don't execute" discipline is enforced
      -by personality + the kanban-orchestrator skill, not by missing tools.
      +by personality + the auto-injected kanban orchestration guidance, not by
      +missing tools.
       
       ## Pre-production roles
       
      @@ -38,7 +39,7 @@ Writes scripts, dialogue, voiceover copy, narration. Use for any video with
       spoken or written words beyond a tagline.
       
       - **Toolsets:** kanban, file
      -- **Skills:** `kanban-worker`, `humanizer` (post-process to strip AI-tells)
      +- **Skills:** `humanizer` (post-process to strip AI-tells)
       - **Outputs:** `script.md`, `narration.md`, `dialogue/scene-NN.md`
       
       ### copywriter
      @@ -47,7 +48,7 @@ Like `writer` but specifically for marketing copy: taglines, CTAs, voiceover
       scripts for product videos.
       
       - **Toolsets:** kanban, file
      -- **Skills:** `kanban-worker`, `humanizer`
      +- **Skills:** `humanizer`
       - **Outputs:** `copy.md`
       
       ### concept-artist / visual-designer
      @@ -58,7 +59,7 @@ follow. Often produces still reference frames using image-generation APIs or
       local skills.
       
       - **Toolsets:** kanban, terminal, file
      -- **Skills:** `kanban-worker` plus any project-specific design skill —
      +- **Skills:** any project-specific design skill —
         `claude-design` (UI/web), `sketch` (quick mockup variants),
         `popular-web-designs` (matching known web aesthetic), `pixel-art` (retro),
         `ascii-art` (terminal/retro), `excalidraw` (hand-drawn frames),
      @@ -71,7 +72,7 @@ Maps the brief to a beat-by-beat shot list with timing. Critical for narrative
       film and music video. Often pairs with a diagramming tool.
       
       - **Toolsets:** kanban, file
      -- **Skills:** `kanban-worker` plus a diagram skill — `excalidraw` (sketch),
      +- **Skills:** a diagram skill — `excalidraw` (sketch),
         `architecture-diagram` (technical/system), `concept-diagrams` (educational/
         scientific)
       - **Outputs:** `storyboard.md` with one row per scene/shot, optional
      @@ -83,7 +84,7 @@ Designs the visual language: framing, color, motion, transitions. Reviews
       generator output for visual consistency. Hands off per-scene `VISUAL_SPEC.md`.
       
       - **Toolsets:** kanban, terminal, file, video, vision
      -- **Skills:** `kanban-worker` plus the visual skill that matches the project
      +- **Skills:** the visual skill that matches the project
         (e.g., `ascii-video` for ASCII work, `manim-video` for explainers,
         `touchdesigner-mcp` for real-time visuals, etc.)
       - **Outputs:** `scenes/scene-NN/VISUAL_SPEC.md`, review comments on renderer
      @@ -124,8 +125,9 @@ instead of overloading one. Each loads a different creative skill.
       | `renderer-video` | (external image-to-video API: Runway / Kling / Luma) | Animating still images in narrative film |
       | `renderer-motion-graphics` | (external — Remotion CLI) | Motion graphics, kinetic typography, UI animations |
       
      -For external-API renderers, the profile holds the API client logic; only
      -`kanban-worker` is loaded, plus the terminal toolset and the API key.
      +For external-API renderers, the profile holds the API client logic; no extra
      +skill is loaded (kanban guidance is auto-injected into every kanban worker),
      +plus the terminal toolset and the API key.
       
       ### image-generator
       
      @@ -133,7 +135,7 @@ Specifically for text-to-image generation. Often produces stills that go to
       `renderer-video` for animation.
       
       - **Toolsets:** kanban, terminal, file
      -- **Skills:** `kanban-worker`, optionally `comfyui` (drives a local
      +- **Skills:** optionally `comfyui` (drives a local
         ComfyUI install for image generation)
       - **External APIs (alternative to local ComfyUI):** FAL, Replicate, OpenAI
         Images, Midjourney
      @@ -146,7 +148,7 @@ ComfyUI's image-to-video workflows locally. Almost always follows
       `image-generator` in narrative film pipelines.
       
       - **Toolsets:** kanban, terminal, file
      -- **Skills:** `kanban-worker`, optionally `comfyui` (for local image-to-video
      +- **Skills:** optionally `comfyui` (for local image-to-video
         workflows like AnimateDiff or WAN)
       - **External APIs:** Runway, Kling, Luma, Pika
       - **Outputs:** `scenes/scene-NN/clip.mp4`
      @@ -159,7 +161,7 @@ spectrograms when the editor or renderer needs a visual reference of the
       audio's energy.
       
       - **Toolsets:** kanban, terminal, file
      -- **Skills:** `kanban-worker`, `songsee` (audio visualization), plus one of:
      +- **Skills:** `songsee` (audio visualization), plus one of:
         - `songwriting-and-ai-music` — when commissioning lyrics + Suno prompts
         - `heartmula` — when generating music with the open-source local model
         - `spotify` — when sourcing existing tracks
      @@ -169,11 +171,11 @@ audio's energy.
       ### voice-talent / narrator
       
       Generates voiceover audio. Calls a TTS API directly; no Hermes skill required
      -beyond `kanban-worker`. The user can also supply pre-recorded VO instead of
      -generation.
      +(kanban guidance is auto-injected into every kanban worker). The user can also
      +supply pre-recorded VO instead of generation.
       
       - **Toolsets:** kanban, terminal, file
      -- **Skills:** `kanban-worker`
      +- **Skills:** none — kanban guidance is auto-injected into every kanban worker
       - **External APIs:** ElevenLabs, OpenAI TTS, etc.
       - **Outputs:** `audio/voiceover/line-NN.mp3`, `audio/voiceover/timeline.mp3`
       
      @@ -183,7 +185,7 @@ Sound effects and ambient design. Often optional unless the brief calls for
       sound design specifically.
       
       - **Toolsets:** kanban, terminal, file
      -- **Skills:** `kanban-worker`, `songsee` for audio-feature visualization when
      +- **Skills:** `songsee` for audio-feature visualization when
         designing to a track
       - **Outputs:** `audio/sfx/*.mp3`
       
      @@ -195,7 +197,7 @@ Assembles the final cut from clips. Uses ffmpeg for stitching, fades,
       transitions. Reviews each clip for pacing and quality before assembly.
       
       - **Toolsets:** kanban, terminal, file
      -- **Skills:** `kanban-worker`
      +- **Skills:** none — kanban guidance is auto-injected into every kanban worker
       - **External tools:** ffmpeg, ffprobe
       - **Outputs:** `output/final.mp4`, `output/final-noaudio.mp4`
       
      @@ -206,7 +208,7 @@ brand-consistent output and the editor just stitches, the colorist is overkill.
       Worth including for narrative film with hero shots.
       
       - **Toolsets:** kanban, terminal, file
      -- **Skills:** `kanban-worker`
      +- **Skills:** none — kanban guidance is auto-injected into every kanban worker
       - **Outputs:** `output/final-graded.mp4`
       
       ### audio-mixer
      @@ -215,7 +217,7 @@ Mixes voiceover + music + SFX into a final audio track. Sets levels, ducks
       music under VO, normalizes loudness (LUFS).
       
       - **Toolsets:** kanban, terminal, file
      -- **Skills:** `kanban-worker`
      +- **Skills:** none — kanban guidance is auto-injected into every kanban worker
       - **External tools:** ffmpeg with `loudnorm` filter, optional `sox`
       - **Outputs:** `audio/final-mix.mp3`
       
      @@ -225,7 +227,7 @@ Burns subtitles into the video, generates SRT, handles accessibility. Can also
       generate captions from audio via Whisper.
       
       - **Toolsets:** kanban, terminal, file
      -- **Skills:** `kanban-worker`
      +- **Skills:** none — kanban guidance is auto-injected into every kanban worker
       - **External tools:** Whisper (CLI or API), ffmpeg subtitle filters
       - **Outputs:** `output/captions.srt`, `output/final-captioned.mp4`
       
      @@ -235,7 +237,7 @@ Final encode + format variants. Produces deliverables for each platform target
       (square for IG, vertical for TikTok, full HD for YouTube, etc.).
       
       - **Toolsets:** kanban, terminal, file
      -- **Skills:** `kanban-worker`
      +- **Skills:** none — kanban guidance is auto-injected into every kanban worker
       - **Outputs:** `output/final-1080.mp4`, `output/final-9x16.mp4`, etc.
       
       ## QA roles
      @@ -248,7 +250,7 @@ quality). Distinct from the cinematographer (who reviews visuals during
       production) and the editor (who reviews for assembly).
       
       - **Toolsets:** kanban, terminal, file, video, vision
      -- **Skills:** `kanban-worker`
      +- **Skills:** none — kanban guidance is auto-injected into every kanban worker
       - **Review tools:** `video_analyze` (native clip review via multimodal LLM),
         `vision_analyze` (frame/thumbnail review), ffprobe
       - **Outputs:** `review-notes.md`, comments on tasks
      @@ -260,7 +262,7 @@ when the brand guidelines are detailed and a generic reviewer might miss
       violations.
       
       - **Toolsets:** kanban, file
      -- **Skills:** `kanban-worker`
      +- **Skills:** none — kanban guidance is auto-injected into every kanban worker
       - **Outputs:** comments + `brand-review.md`
       
       ## Composing teams — heuristics
    • optional-skills/creative/kanban-video-orchestrator/references/tool-matrix.md
      @@ -50,18 +50,12 @@ called from the terminal toolset; they don't appear in `always_load`.
       | `gif-search` | Find existing GIFs | Editor / concept artist sourcing references |
       | `gifs` | GIF tooling | Masterer producing GIF deliverables |
       
      -### Kanban infrastructure (`hermes-agent/skills/devops/`)
      -
      -| Skill | What it does | When to load |
      -|-------|--------------|--------------|
      -| `kanban-orchestrator` | Decomposition playbook + anti-temptation rules for orchestrator profiles | Director only |
      -| `kanban-worker` | Pitfalls, examples, edge cases for kanban workers (deeper than auto-injected guidance) | Any profile — load when handling tricky multi-step workflows |
      +### Kanban infrastructure
       
       The kanban plugin auto-injects baseline orchestration guidance into every
       worker's system prompt — the `kanban_create` fan-out pattern, claim/handoff
      -lifecycle, and the "decompose, don't execute" rule for orchestrators.
      -`kanban-orchestrator` and `kanban-worker` are deeper playbooks loaded when a
      -profile needs them.
      +lifecycle, and the "decompose, don't execute" rule for orchestrators. There is
      +no kanban skill to load; the guidance is always present for kanban workers.
       
       ## External tools (called from terminal toolset)
       
      @@ -102,8 +96,7 @@ toolsets:
         - terminal
         - file
       skills:
      -  always_load:
      -    - kanban-orchestrator
      +  always_load: []
       ```
       
       The director's terminal access is conventional but the SOUL.md rules forbid
      @@ -117,7 +110,6 @@ toolsets:
         - file
       skills:
         always_load:
      -    - kanban-worker
           - humanizer            # post-process scripts to strip AI-tells
       ```
       
      @@ -132,7 +124,6 @@ toolsets:
         - file
       skills:
         always_load:
      -    - kanban-worker
           # plus one or more (style-dependent):
           # - claude-design       (UI / web product video)
           # - sketch              (quick mockup variants)
      @@ -151,7 +142,6 @@ toolsets:
         - file
       skills:
         always_load:
      -    - kanban-worker
           # one of:
           # - excalidraw              (sketch storyboards)
           # - architecture-diagram    (technical/system content)
      @@ -169,7 +159,6 @@ toolsets:
         - vision              # vision_analyze — review stills / exported frames
       skills:
         always_load:
      -    - kanban-worker
           # the visual skill that matches the project, e.g.:
           # - ascii-video            (ASCII projects)
           # - manim-video            (math/explainer)
      @@ -188,7 +177,6 @@ toolsets:
         - file
       skills:
         always_load:
      -    - kanban-worker
           # ONE skill per renderer variant (or empty for external-API renderers):
           # - ascii-video               (renderer-ascii)
           # - manim-video               (renderer-manim)
      @@ -202,9 +190,9 @@ skills:
       ```
       
       For external-API renderers (image-to-video-generator using Runway, voice-talent
      -using ElevenLabs, renderer-motion-graphics using Remotion), `always_load` only
      -contains `kanban-worker` — the role's work is API-driven and the API key +
      -terminal commands suffice.
      +using ElevenLabs, renderer-motion-graphics using Remotion), `always_load` is
      +empty — the role's work is API-driven and the API key +
      +terminal commands suffice (kanban guidance is auto-injected regardless).
       
       For multi-skill renderer setups (rare — usually one variant per skill is
       cleaner) use `--skill <name>` on individual `kanban_create` calls to override
      @@ -219,7 +207,6 @@ toolsets:
         - file
       skills:
         always_load:
      -    - kanban-worker
           # for image-generator that drives ComfyUI locally:
           # - comfyui
       env_required:
      @@ -242,7 +229,6 @@ toolsets:
         - file
       skills:
         always_load:
      -    - kanban-worker
           - songsee                         # spectrograms / audio analysis
           # plus (depending on what the project needs):
           # - songwriting-and-ai-music      (commissioning Suno tracks)
      @@ -260,11 +246,11 @@ toolsets:
         - video              # video_analyze — editor reviews assembled cuts natively
         - vision             # vision_analyze — spot-check frames
       skills:
      -  always_load:
      -    - kanban-worker
      +  always_load: []
       ```
       
      -These are mostly ffmpeg-driven; no special skill needed beyond `kanban-worker`.
      +These are mostly ffmpeg-driven; no special skill needed (kanban guidance is
      +auto-injected into every kanban worker).
       For captioner add Whisper invocation patterns to the SOUL.md.
       
       ### reviewer / brand-cop
      @@ -277,8 +263,7 @@ toolsets:
         - video              # video_analyze — review full clips natively
         - vision             # vision_analyze — review stills / exported frames
       skills:
      -  always_load:
      -    - kanban-worker
      +  always_load: []
       ```
       
       ## API key requirements
    • optional-skills/creative/kanban-video-orchestrator/scripts/bootstrap_pipeline.py
      @@ -423,8 +423,6 @@ def render_soul_md(team_member: dict, plan: dict) -> str:
                   "- **Decompose, route, comment, approve — that's the whole job.**\n"
                   "- **Read TEAM.md** for the canonical task graph. Do not invent "
                   "new roles unless the brief truly demands it.\n"
      -            "- **Load the `kanban-orchestrator` skill** for the deeper "
      -            "decomposition playbook beyond the auto-injected baseline.\n"
               )
       
           common_commands = (
    • /dev/null
      @@ -1,214 +0,0 @@
      ----
      -name: kanban-orchestrator
      -description: Decomposition playbook + anti-temptation rules for an orchestrator profile routing work through Kanban. The "don't do the work yourself" rule and the basic lifecycle are auto-injected into every kanban worker's system prompt; this skill is the deeper playbook when you're specifically playing the orchestrator role.
      -version: 3.0.0
      -platforms: [linux, macos, windows]
      -environments: [kanban]
      -metadata:
      -  hermes:
      -    tags: [kanban, multi-agent, orchestration, routing]
      -    related_skills: [kanban-worker]
      ----
      -
      -# Kanban Orchestrator — Decomposition Playbook
      -
      -> The **core worker lifecycle** (including the `kanban_create` fan-out pattern and the "decompose, don't execute" rule) is auto-injected into every kanban process via the `KANBAN_GUIDANCE` system-prompt block. This skill is the deeper playbook when you're an orchestrator profile whose whole job is routing.
      -
      -## Profiles are user-configured — not a fixed roster
      -
      -Hermes setups vary widely. Some users run a single profile that does everything; some run a small fleet (`docker-worker`, `cron-worker`); some run a curated specialist team they've named themselves. There is **no default specialist roster** — the orchestrator skill does not know what profiles exist on this machine.
      -
      -Before fanning out, you must ground the decomposition in the profiles that actually exist. The dispatcher silently fails to spawn unknown assignee names — it doesn't autocorrect, doesn't suggest, doesn't fall back. So a card assigned to `researcher` on a setup that only has `docker-worker` just sits in `ready` forever.
      -
      -**Step 0: discover available profiles before planning.**
      -
      -Use one of these:
      -
      -- `hermes profile list` — prints the table of profiles configured on this machine. Run it through your terminal tool if you have one; otherwise ask the user.
      -- `kanban_list(assignee="<some-name>")` — sanity-check a single name. Returns an empty list (rather than an error) for an unknown assignee, so this only confirms a name you're already considering.
      -- **Just ask the user.** "What profiles do you have set up?" is a fine first turn when the goal needs more than one specialist.
      -
      -Cache the result in your working memory for the rest of the conversation. Re-asking every turn wastes a tool call.
      -
      -## When to use the board (vs. just doing the work)
      -
      -Create Kanban tasks when any of these are true:
      -
      -1. **Multiple specialists are needed.** Research + analysis + writing is three profiles.
      -2. **The work should survive a crash or restart.** Long-running, recurring, or important.
      -3. **The user might want to interject.** Human-in-the-loop at any step.
      -4. **Multiple subtasks can run in parallel.** Fan-out for speed.
      -5. **Review / iteration is expected.** A reviewer profile loops on drafter output.
      -6. **The audit trail matters.** Board rows persist in SQLite forever.
      -
      -If *none* of those apply — it's a small one-shot reasoning task — use `delegate_task` instead or answer the user directly.
      -
      -## The anti-temptation rules
      -
      -Your job description says "route, don't execute." The rules that enforce that:
      -
      -- **Do not execute the work yourself.** Your restricted toolset usually doesn't even include terminal/file/code/web for implementation. If you find yourself "just fixing this quickly" — stop and create a task for the right specialist.
      -- **For any concrete task, create a Kanban task and assign it.** Every single time.
      -- **Split multi-lane requests before creating cards.** A user prompt can contain several independent workstreams. Extract those lanes first, then create one card per lane instead of bundling unrelated work into a single implementer card.
      -- **Run independent lanes in parallel.** If two cards do not need each other's output, leave them unlinked so the dispatcher can fan them out. Link only true data dependencies.
      -- **Never create dependent work as independent ready cards.** If a card must wait for another card, pass `parents=[...]` in the original `kanban_create` call. Do not create it first and link it later, and do not rely on prose like "wait for T1" inside the body.
      -- **If no specialist fits the available profiles, ask the user which profile to create or which existing profile to use.** Do not invent profile names; the dispatcher will silently drop unknown assignees.
      -- **Decompose, route, and summarize — that's the whole job.**
      -
      -## Decomposition playbook
      -
      -### Step 1 — Understand the goal
      -
      -Ask clarifying questions if the goal is ambiguous. Cheap to ask; expensive to spawn the wrong fleet.
      -
      -### Step 2 — Sketch the task graph
      -
      -Before creating anything, draft the graph out loud (in your response to the user). Treat every concrete workstream as a candidate card:
      -
      -1. Extract the lanes from the request.
      -2. Map each lane to one of the profiles you discovered in Step 0. If a lane doesn't fit any existing profile, ask the user which to use or create.
      -3. Decide whether each lane is independent or gated by another lane.
      -4. Create independent lanes as parallel cards with no parent links.
      -5. Create synthesis/review/integration cards with parent links to the lanes they depend on. A child created with unfinished parents starts in `todo`; the dispatcher promotes it to `ready` only after every parent is done.
      -
      -Examples of prompts that should fan out (using placeholder profile names — substitute whatever exists on the user's setup):
      -
      -- "Build an app" → one card to a design-oriented profile for product/UI direction, one or two cards to engineering profiles for implementation, plus a later integration/review card if the user has a reviewer profile.
      -- "Fix blockers and check model variants" → one implementation card for the blocker fixes plus one discovery/research card for config/source verification. A final reviewer card can depend on both.
      -- "Research docs and implement" → a docs-research card can run in parallel with a codebase-discovery card; implementation waits only if it truly needs those findings.
      -- "Analyze this screenshot and find the related code" → one card to a vision-capable profile for the visual analysis while another searches the codebase.
      -
      -Words like "also," "finally," or "and" do not automatically imply a dependency. They often mean "make sure this is covered before reporting back." Only link tasks when one card cannot start until another card's output exists.
      -
      -Show the graph to the user before creating cards. Let them correct it — including which actual profile name should own each lane.
      -
      -### Step 3 — Create tasks and link
      -
      -Use the profile names from Step 0. The example below uses placeholders `<profile-A>`, `<profile-B>`, `<profile-C>` — replace them with what the user actually has.
      -
      -```python
      -t1 = kanban_create(
      -    title="research: Postgres cost vs current",
      -    assignee="<profile-A>",  # whichever profile handles research on this setup
      -    body="Compare estimated infrastructure costs, migration costs, and ongoing ops costs over a 3-year window. Sources: AWS/GCP pricing, team time estimates, current Postgres bills from peers.",
      -    tenant=os.environ.get("HERMES_TENANT"),
      -)["task_id"]
      -
      -t2 = kanban_create(
      -    title="research: Postgres performance vs current",
      -    assignee="<profile-A>",  # same profile, run in parallel
      -    body="Compare query latency, throughput, and scaling characteristics at our expected data volume (~500GB, 10k QPS peak). Sources: benchmark papers, public case studies, pgbench results if easy.",
      -)["task_id"]
      -
      -t3 = kanban_create(
      -    title="synthesize migration recommendation",
      -    assignee="<profile-B>",  # whichever profile does synthesis/analysis
      -    body="Read the findings from T1 (cost) and T2 (performance). Produce a 1-page recommendation with explicit trade-offs and a go/no-go call.",
      -    parents=[t1, t2],
      -)["task_id"]
      -
      -t4 = kanban_create(
      -    title="draft decision memo",
      -    assignee="<profile-C>",  # whichever profile drafts user-facing prose
      -    body="Turn the analyst's recommendation into a 2-page memo for the CTO. Match the tone of previous decision memos in the team's knowledge base.",
      -    parents=[t3],
      -)["task_id"]
      -```
      -
      -`parents=[...]` gates promotion — children stay in `todo` until every parent reaches `done`, then auto-promote to `ready`. No manual coordination needed; the dispatcher and dependency engine handle it.
      -
      -If the task graph has dependencies, create the parent cards first, capture their returned ids, and include those ids in the child card's `parents` list during the child `kanban_create` call. Avoid creating all cards in parallel and linking them afterward; that creates a window where the dispatcher can claim a child before its inputs exist.
      -
      -### Step 4 — Complete your own task
      -
      -If you were spawned as a task yourself (e.g. a planner profile was assigned `T0: "investigate Postgres migration"`), mark it done with a summary of what you created:
      -
      -```python
      -kanban_complete(
      -    summary="decomposed into T1-T4: 2 research lanes in parallel, 1 synthesis on their outputs, 1 prose draft on the recommendation",
      -    metadata={
      -        "task_graph": {
      -            "T1": {"assignee": "<profile-A>", "parents": []},
      -            "T2": {"assignee": "<profile-A>", "parents": []},
      -            "T3": {"assignee": "<profile-B>", "parents": ["T1", "T2"]},
      -            "T4": {"assignee": "<profile-C>", "parents": ["T3"]},
      -        },
      -    },
      -)
      -```
      -
      -### Step 5 — Report back to the user
      -
      -Tell them what you created in plain prose, naming the actual profiles you used:
      -
      -> I've queued 4 tasks:
      -> - **T1** (`<profile-A>`): cost comparison
      -> - **T2** (`<profile-A>`): performance comparison, in parallel with T1
      -> - **T3** (`<profile-B>`): synthesizes T1 + T2 into a recommendation
      -> - **T4** (`<profile-C>`): turns T3 into a CTO memo
      ->
      -> The dispatcher will pick up T1 and T2 now. T3 starts when both finish. You'll get a gateway ping when T4 completes. Use the dashboard or `hermes kanban tail <id>` to follow along.
      -
      -## Common patterns
      -
      -**Fan-out + fan-in (research → synthesize):** N research-style cards with no parents, one synthesis card with all of them as parents.
      -
      -**Parallel implementation + validation:** one implementer card makes the change while one explorer/researcher card verifies config, docs, or source mapping. A reviewer card can depend on both. Do not make the implementer own unrelated verification just because the user mentioned both in one sentence.
      -
      -**Pipeline with gates:** `planner → implementer → reviewer`. Each stage's `parents=[previous_task]`. Reviewer blocks or completes; if reviewer blocks, the operator unblocks with feedback and respawns.
      -
      -**Same-profile queue:** N tasks, all assigned to the same profile, no dependencies between them. Dispatcher serializes — that profile processes them in priority order, accumulating experience in its own memory.
      -
      -**Human-in-the-loop:** Any task can `kanban_block()` to wait for input. Dispatcher respawns after `/unblock`. The comment thread carries the full context.
      -
      -## Pitfalls
      -
      -**Inventing profile names that don't exist.** The dispatcher silently fails to spawn unknown assignees — the card just sits in `ready` forever. Always assign to a profile from your Step 0 discovery; ask the user if you're unsure.
      -
      -**Bundling independent lanes into one card.** If the user asks for two independent outcomes, create two cards. Example: "fix blockers and check model variants" is not one fixer task; create a fixer/engineer card for the fixes and an explorer/researcher card for the variant check, then optionally gate review on both.
      -
      -**Over-linking because of wording.** "Finally check X" may still be parallel with implementation if X is static config, docs, or source discovery. Link it after implementation only when the check depends on the implementation result.
      -
      -**Forgetting dependency links.** If the task graph says `research -> implement -> review`, do not create all tasks as independent ready cards. Use parent links so implement/review cannot run before their inputs exist.
      -
      -**Reassignment vs. new task.** If a reviewer blocks with "needs changes," create a NEW task linked from the reviewer's task — don't re-run the same task with a stern look. The new task is assigned to the original implementer profile.
      -
      -**Argument order for links.** `kanban_link(parent_id=..., child_id=...)` — parent first. Mixing them up demotes the wrong task to `todo`.
      -
      -**Don't pre-create the whole graph if the shape depends on intermediate findings.** If T3's structure depends on what T1 and T2 find, let T3 exist as a "synthesize findings" task whose own first step is to read parent handoffs and plan the rest. Orchestrators can spawn orchestrators.
      -
      -**Tenant inheritance.** If `HERMES_TENANT` is set in your env, pass `tenant=os.environ.get("HERMES_TENANT")` on every `kanban_create` call so child tasks stay in the same namespace.
      -
      -## Goal-mode cards (persistent workers)
      -
      -By default a dispatched worker gets **one shot** at its card: it does its work, calls `kanban_complete`/`kanban_block`, and exits. For open-ended cards where one turn rarely finishes the job, pass `goal_mode=True` to wrap that worker in a Ralph-style goal loop — the same engine behind the `/goal` slash command:
      -
      -```python
      -kanban_create(
      -    title="Translate the full docs site to French",
      -    body="Acceptance: every page translated, no English left, links intact.",
      -    assignee="<translator-profile>",
      -    goal_mode=True,        # judge re-checks the card after each turn
      -    goal_max_turns=15,     # optional budget (default 20)
      -)["task_id"]
      -```
      -
      -How it behaves:
      -- After each worker turn, an auxiliary judge evaluates the worker's response against the card's **title + body** (treated as the acceptance criteria).
      -- Not done + budget remains → the worker keeps going **in the same session** (full context retained — not a fresh respawn).
      -- Worker calls `kanban_complete`/`kanban_block` itself → loop stops, normal lifecycle.
      -- Budget exhausted without completion → the card is **blocked** for human review (sticky), never a silent exit.
      -
      -When to use it: long, multi-step, or "keep going until X is true" cards. When NOT to: cheap one-shot cards (translation of a single string, a quick lookup) — the judge overhead isn't worth it, and the dispatcher's existing retry/circuit-breaker already handles transient worker failures.
      -
      -Write the body as **explicit acceptance criteria** — the judge is only as good as the goal text. "Translate the README" is weaker than "Translate every section of the README to French; no English sentences remain."
      -
      -## Recovering stuck workers
      -
      -When a worker profile keeps crashing, hallucinating, or getting blocked by its own mistakes (usually: wrong model, missing skill, broken credential), the kanban dashboard flags the task with a ⚠ badge and opens a **Recovery** section in the drawer. Three primary actions:
      -
      -1. **Reclaim** (or `hermes kanban reclaim <task_id>`) — abort the running worker immediately and reset the task to `ready`. The existing claim TTL is ~15 min; this is the fast path out.
      -2. **Reassign** (or `hermes kanban reassign <task_id> <new-profile> --reclaim`) — switch the task to a different profile (one that exists on this setup) and let the dispatcher pick it up with a fresh worker.
      -3. **Change profile model** — the dashboard prints a copy-paste hint for `hermes -p <profile> model` since profile config lives on disk; edit it in a terminal, then Reclaim to retry with the new model.
      -
      -Hallucination warnings appear on tasks where a worker's `kanban_complete(created_cards=[...])` claim included card ids that don't exist or weren't created by the worker's profile (the gate blocks the completion), or where the free-form summary references `t_<hex>` ids that don't resolve (advisory prose scan, non-blocking). Both produce audit events that persist even after recovery actions — the trail stays for debugging.
    • /dev/null
      @@ -1,214 +0,0 @@
      ----
      -name: kanban-worker
      -description: Pitfalls, examples, and edge cases for Hermes Kanban workers. The lifecycle itself is auto-injected into every worker's system prompt as KANBAN_GUIDANCE (from agent/prompt_builder.py); this skill is what you load when you want deeper detail on specific scenarios.
      -version: 2.0.0
      -platforms: [linux, macos, windows]
      -environments: [kanban]
      -metadata:
      -  hermes:
      -    tags: [kanban, multi-agent, collaboration, workflow, pitfalls]
      -    related_skills: [kanban-orchestrator]
      ----
      -
      -# Kanban Worker — Pitfalls and Examples
      -
      -> You're seeing this skill because the Hermes Kanban dispatcher spawned you as a worker with `--skills kanban-worker` — it's loaded automatically for every dispatched worker. The **lifecycle** (6 steps: orient → work → heartbeat → block/complete) also lives in the `KANBAN_GUIDANCE` block that's auto-injected into your system prompt. This skill is the deeper detail: good handoff shapes, retry diagnostics, edge cases.
      -
      -## Workspace handling
      -
      -Your workspace kind determines how you should behave inside `$HERMES_KANBAN_WORKSPACE`:
      -
      -| Kind | What it is | How to work |
      -|---|---|---|
      -| `scratch` | Fresh tmp dir, yours alone | Read/write freely; it gets GC'd when the task is archived. |
      -| `dir:<path>` | Shared persistent directory | Other runs will read what you write. Treat it like long-lived state. Path is guaranteed absolute (the kernel rejects relative paths). |
      -| `worktree` | Git worktree at the resolved path | If `.git` doesn't exist, run `git worktree add <path> ${HERMES_KANBAN_BRANCH:-wt/$HERMES_KANBAN_TASK}` from the main repo first, then cd and work normally. Commit work here. |
      -
      -## Tenant isolation
      -
      -If `$HERMES_TENANT` is set, the task belongs to a tenant namespace. When reading or writing persistent memory, prefix memory entries with the tenant so context doesn't leak across tenants:
      -
      -- Good: `business-a: Acme is our biggest customer`
      -- Bad (leaks): `Acme is our biggest customer`
      -
      -## Good summary + metadata shapes
      -
      -The `kanban_complete(summary=..., metadata=...)` handoff is how downstream workers read what you did. Patterns that work:
      -
      -**Coding task:**
      -```python
      -kanban_complete(
      -    summary="shipped rate limiter — token bucket, keys on user_id with IP fallback, 14 tests pass",
      -    metadata={
      -        "changed_files": ["rate_limiter.py", "tests/test_rate_limiter.py"],
      -        "tests_run": 14,
      -        "tests_passed": 14,
      -        "decisions": ["user_id primary, IP fallback for unauthenticated requests"],
      -    },
      -)
      -```
      -
      -**Coding task that needs human review (review-required):**
      -
      -For most code-changing tasks, the work isn't truly *done* until a human reviewer has eyes on it. Block instead of complete, with `reason` prefixed `review-required: ` so the dashboard surfaces the row as needing review. Drop the structured metadata (changed files, test counts, diff/PR url) into a comment first, since `kanban_block` only carries the human-readable reason — comments are the durable annotation channel. Reviewer either approves and runs `hermes kanban unblock <id>` (which re-spawns you with the comment thread for any follow-ups) or asks for changes via another comment.
      -
      -```python
      -import json
      -
      -kanban_comment(
      -    body="review-required handoff:\n" + json.dumps({
      -        "changed_files": ["rate_limiter.py", "tests/test_rate_limiter.py"],
      -        "tests_run": 14,
      -        "tests_passed": 14,
      -        "diff_path": "/path/to/worktree",  # or PR url if pushed
      -        "decisions": ["user_id primary, IP fallback for unauthenticated requests"],
      -    }, indent=2),
      -)
      -kanban_block(
      -    reason="review-required: rate limiter shipped, 14/14 tests pass — needs eyes on the user_id/IP fallback choice before merging",
      -)
      -```
      -
      -Use `kanban_complete` only when the task is genuinely terminal — e.g. a one-line typo fix, a docs change with no functional consequences, or a research task where the artifact IS the writeup itself.
      -
      -**Research task:**
      -```python
      -kanban_complete(
      -    summary="3 competing libraries reviewed; vLLM wins on throughput, SGLang on latency, Tensorrt-LLM on memory efficiency",
      -    metadata={
      -        "sources_read": 12,
      -        "recommendation": "vLLM",
      -        "benchmarks": {"vllm": 1.0, "sglang": 0.87, "trtllm": 0.72},
      -    },
      -)
      -```
      -
      -**Review task:**
      -```python
      -kanban_complete(
      -    summary="reviewed PR #123; 2 blocking issues found (SQL injection in /search, missing CSRF on /settings)",
      -    metadata={
      -        "pr_number": 123,
      -        "findings": [
      -            {"severity": "critical", "file": "api/search.py", "line": 42, "issue": "raw SQL concat"},
      -            {"severity": "high", "file": "api/settings.py", "issue": "missing CSRF middleware"},
      -        ],
      -        "approved": False,
      -    },
      -)
      -```
      -
      -Shape `metadata` so downstream parsers (reviewers, aggregators, schedulers) can use it without re-reading your prose.
      -
      -## Shipping deliverables (`artifacts=[...]`)
      -
      -If your task produced files a human actually wants — a chart, a PDF, a spreadsheet, a generated image, an archive — pass their **absolute paths** to `kanban_complete(artifacts=[...])`. The gateway notifier uploads each one as a native attachment to whoever subscribed to the task, so the deliverable lands in their chat alongside the completion message instead of being a path they have to go fetch.
      -
      -```python
      -kanban_complete(
      -    summary="Q3 revenue analysis: 14% QoQ growth, EMEA the laggard. Chart + full PDF attached.",
      -    artifacts=["/tmp/q3-revenue.png", "/tmp/q3-report.pdf"],
      -    metadata={"rows_analyzed": 48000, "growth_qoq": 0.14},
      -)
      -```
      -
      -Images and video embed inline; PDFs, docx, csv/xlsx/json/yaml, pptx, zip/tar/gz, audio, and html upload as files. Rules:
      -
      -- **Absolute paths only**, and the file must still exist when you complete — don't point at a scratch file you already deleted.
      -- **Only real deliverables.** Skip intermediate logs, scratch files, and inputs the human already has.
      -- `artifacts` is the **top-level** parameter the notifier reads. Do not bury deliverable paths in `metadata` (e.g. `metadata.codex_lane.artifacts`) and expect them to upload — the notifier only scans the top-level `artifacts` list, with a best-effort fallback over your `summary`/`result` text. Metadata paths are for downstream-worker bookkeeping, not delivery.
      -- A bare string is auto-promoted to a one-element list, and it merges with any pre-existing `metadata.artifacts` without dupes.
      -
      -Same primitive works outside kanban: any agent surface delivers a file just by writing its absolute path into the response, and Slack/Discord/Telegram/etc. upload it natively — the `artifacts` param is the structured kanban entry point.
      -
      -## Claiming cards you actually created
      -
      -If your run produced new kanban tasks (via `kanban_create`), pass the ids in `created_cards` on `kanban_complete`. The kernel verifies each id exists and was created by your profile; any phantom id blocks the completion with an error listing what went wrong, and the rejected attempt is permanently recorded on the task's event log. **Only list ids you captured from a successful `kanban_create` return value — never invent ids from prose, never paste ids from earlier runs, never claim cards another worker created.**
      -
      -```python
      -# GOOD — capture return values, then claim them.
      -c1 = kanban_create(title="remediate SQL injection", assignee="security-worker")
      -c2 = kanban_create(title="fix CSRF middleware", assignee="web-worker")
      -
      -kanban_complete(
      -    summary="Review done; spawned remediations for both findings.",
      -    metadata={"pr_number": 123, "approved": False},
      -    created_cards=[c1["task_id"], c2["task_id"]],
      -)
      -```
      -
      -```python
      -# BAD — claiming ids you don't have captured return values for.
      -kanban_complete(
      -    summary="Created remediation cards t_a1b2c3d4, t_deadbeef",  # hallucinated
      -    created_cards=["t_a1b2c3d4", "t_deadbeef"],                   # → gate rejects
      -)
      -```
      -
      -If a `kanban_create` call fails (exception, tool_error), the card was NOT created — do not include a phantom id for it. Retry the create, or omit the id and mention the failure in your summary. The prose-scan pass also catches `t_<hex>` references in your free-form summary that don't resolve; these don't block the completion but show up as advisory warnings on the task in the dashboard.
      -
      -## Block reasons that get answered fast
      -
      -Bad: `"stuck"` — the human has no context.
      -
      -Good: one sentence naming the specific decision you need. Leave longer context as a comment instead.
      -
      -```python
      -kanban_comment(
      -    task_id=os.environ["HERMES_KANBAN_TASK"],
      -    body="Full context: I have user IPs from Cloudflare headers but some users are behind NATs with thousands of peers. Keying on IP alone causes false positives.",
      -)
      -kanban_block(reason="Rate limit key choice: IP (simple, NAT-unsafe) or user_id (requires auth, skips anonymous endpoints)?")
      -```
      -
      -The block message is what appears in the dashboard / gateway notifier. The comment is the deeper context a human reads when they open the task.
      -
      -## Heartbeats worth sending
      -
      -Good heartbeats name progress: `"epoch 12/50, loss 0.31"`, `"scanned 1.2M/2.4M rows"`, `"uploaded 47/120 videos"`.
      -
      -Bad heartbeats: `"still working"`, empty notes, sub-second intervals. Every few minutes max; skip entirely for tasks under ~2 minutes.
      -
      -## Retry scenarios
      -
      -If you open the task and `kanban_show` returns `runs: [...]` with one or more closed runs, you're a retry. The prior runs' `outcome` / `summary` / `error` tell you what didn't work. Don't repeat that path. Typical retry diagnostics:
      -
      -- `outcome: "timed_out"` — the previous attempt hit `max_runtime_seconds`. You may need to chunk the work or shorten it.
      -- `outcome: "crashed"` — OOM or segfault. Reduce memory footprint.
      -- `outcome: "spawn_failed"` + `error: "..."` — usually a profile config issue (missing credential, bad PATH). Ask the human via `kanban_block` instead of retrying blindly.
      -- `outcome: "reclaimed"` + `summary: "task archived..."` — operator archived the task out from under the previous run; you probably shouldn't be running at all, check status carefully.
      -- `outcome: "blocked"` — a previous attempt blocked; the unblock comment should be in the thread by now.
      -
      -## Notification routing
      -
      -You can configure the gateway to receive cross-profile Kanban task notifications by adding `notification_sources` to `~/.hermes/config.yaml`.
      -- `notification_sources: ['*']` accepts subscriptions from all profiles.
      -- `notification_sources: ['default', 'zilor-ppt']` or `"default,zilor-ppt"` restricts subscriptions to specified profiles.
      -- Omitting the key keeps the default behavior (profile isolation).
      -
      -## Do NOT
      -
      -- Call `delegate_task` as a substitute for `kanban_create`. `delegate_task` is for short reasoning subtasks inside YOUR run; `kanban_create` is for cross-agent handoffs that outlive one API loop.
      -- Call `clarify` to ask the human a question. You are running headless — there is no live user to answer. The call will time out (default ~120s) and the task will sit silently in `running` with no signal that it needs input. Use `kanban_comment` (context) + `kanban_block(reason=...)` (decision needed) instead — the task surfaces on the board as blocked, the operator sees it, unblocks with their answer in a comment, and you respawn with the thread.
      -- Modify files outside `$HERMES_KANBAN_WORKSPACE` unless the task body says to.
      -- Create follow-up tasks assigned to yourself — assign to the right specialist.
      -- Complete a task you didn't actually finish. Block it instead.
      -
      -## Pitfalls
      -
      -**Task state can change between dispatch and your startup.** Between when the dispatcher claimed and when your process actually booted, the task may have been blocked, reassigned, or archived. Always `kanban_show` first. If it reports `blocked` or `archived`, stop — you shouldn't be running.
      -
      -**Workspace may have stale artifacts.** Especially `dir:` and `worktree` workspaces can have files from previous runs. Read the comment thread — it usually explains why you're running again and what state the workspace is in.
      -
      -**Don't rely on the CLI when the guidance is available.** The `kanban_*` tools work across all terminal backends (Docker, Modal, SSH). `hermes kanban <verb>` from your terminal tool will fail in containerized backends because the CLI isn't installed there. When in doubt, use the tool.
      -
      -## CLI fallback (for scripting)
      -
      -Every tool has a CLI equivalent for human operators and scripts:
      -- `kanban_show` ↔ `hermes kanban show <id> --json`
      -- `kanban_complete` ↔ `hermes kanban complete <id> --summary "..." --metadata '{...}'`
      -- `kanban_block` ↔ `hermes kanban block <id> "reason"`
      -- `kanban_create` ↔ `hermes kanban create "title" --assignee <profile> [--parent <id>]`
      -- etc.
      -
      -Use the tools from inside an agent; the CLI exists for the human at the terminal.
    • tests/hermes_cli/test_kanban_core_functionality.py
      @@ -2703,20 +2703,17 @@ def test_build_worker_context_caps_huge_summary(kanban_home):
               conn.close()
       
       
      -def test_default_spawn_auto_loads_kanban_worker_skill(kanban_home, monkeypatch):
      -    """The dispatcher's _default_spawn must include --skills kanban-worker
      -    in its argv so every worker loads the skill automatically, even if
      -    the profile hasn't wired it into its default skills config.
      +def test_default_spawn_does_not_auto_load_any_skill(kanban_home, monkeypatch):
      +    """The dispatcher no longer auto-loads a bundled kanban skill.
      +
      +    The kanban lifecycle (formerly the kanban-worker/kanban-orchestrator
      +    skills) is now injected into every worker's system prompt via
      +    KANBAN_GUIDANCE, so _default_spawn must NOT append a `--skills` flag
      +    when the task carries no per-task skills.
       
           We intercept Popen to capture the argv without actually spawning a
           hermes subprocess (which would hang trying to call an LLM).
           """
      -    # Pretend the bundled kanban-worker skill resolves for this isolated
      -    # HERMES_HOME — the fixture creates an empty tmpdir without the
      -    # devops/kanban-worker tree, and _default_spawn gates the --skills
      -    # flag on actual resolvability.
      -    monkeypatch.setattr(kb, "_kanban_worker_skill_available", lambda _h: True)
      -
           captured = {}
       
           class FakeProc:
      @@ -2742,10 +2739,8 @@ def fake_popen(cmd, **kwargs):
               conn.close()
       
           cmd = captured["cmd"]
      -    assert "--skills" in cmd, f"spawn argv missing --skills: {cmd}"
      -    idx = cmd.index("--skills")
      -    assert cmd[idx + 1] == "kanban-worker", (
      -        f"expected 'kanban-worker', got {cmd[idx + 1]!r}"
      +    assert "--skills" not in cmd, (
      +        f"spawn argv should not auto-load any skill: {cmd}"
           )
           assert "--accept-hooks" in cmd, f"spawn argv missing --accept-hooks: {cmd}"
           assert cmd.index("--accept-hooks") < cmd.index("chat"), (
      @@ -2985,8 +2980,7 @@ def test_create_task_skills_lists_all_toolset_typos(kanban_home):
       
       def test_default_spawn_appends_per_task_skills(kanban_home, monkeypatch):
           """Dispatcher argv must carry one `--skills X` pair per task skill,
      -    in addition to the built-in kanban-worker."""
      -    monkeypatch.setattr(kb, "_kanban_worker_skill_available", lambda _h: True)
      +    in declared order. No skill is auto-loaded anymore."""
           captured = {}
       
           class FakeProc:
      @@ -3019,10 +3013,8 @@ def fake_popen(cmd, **kwargs):
           for i, tok in enumerate(cmd):
               if tok == "--skills" and i + 1 < len(cmd):
                   skill_names.append(cmd[i + 1])
      -    # kanban-worker first (built-in), then per-task extras in order.
      -    assert skill_names[0] == "kanban-worker", skill_names
      -    assert "translation" in skill_names
      -    assert "github-code-review" in skill_names
      +    # Only the per-task skills, in declared order — nothing auto-loaded.
      +    assert skill_names == ["translation", "github-code-review"], skill_names
           # --skills must appear BEFORE the `chat` subcommand so argparse
           # attaches them to the top-level parser, not the subcommand.
           chat_idx = cmd.index("chat")
      @@ -3034,9 +3026,9 @@ def fake_popen(cmd, **kwargs):
           )
       
       
      -def test_default_spawn_dedupes_kanban_worker_from_task_skills(kanban_home, monkeypatch):
      -    """If a task explicitly lists 'kanban-worker', we don't double-pass it."""
      -    monkeypatch.setattr(kb, "_kanban_worker_skill_available", lambda _h: True)
      +def test_default_spawn_passes_task_skills_verbatim(kanban_home, monkeypatch):
      +    """Per-task skills are passed through verbatim — there is no built-in
      +    kanban skill to dedupe against anymore."""
           captured = {}
       
           class FakeProc:
      @@ -3052,7 +3044,7 @@ def fake_popen(cmd, **kwargs):
           try:
               tid = kb.create_task(
                   conn, title="dup", assignee="x",
      -            skills=["kanban-worker", "translation"],
      +            skills=["translation", "github-code-review"],
               )
               task = kb.get_task(conn, tid)
               workspace = kb.resolve_workspace(task)
      @@ -3061,12 +3053,14 @@ def fake_popen(cmd, **kwargs):
               conn.close()
       
           cmd = captured["cmd"]
      -    worker_pairs = [
      -        i for i, tok in enumerate(cmd)
      -        if tok == "--skills" and i + 1 < len(cmd) and cmd[i + 1] == "kanban-worker"
      +    skill_names = [
      +        cmd[i + 1]
      +        for i, tok in enumerate(cmd)
      +        if tok == "--skills" and i + 1 < len(cmd)
           ]
      -    assert len(worker_pairs) == 1, (
      -        f"kanban-worker appeared {len(worker_pairs)} times in argv: {cmd}"
      +    # Exactly the task's skills, once each, in order — no auto-loaded extras.
      +    assert skill_names == ["translation", "github-code-review"], (
      +        f"unexpected --skills in argv: {cmd}"
           )
       
       
    • tests/hermes_cli/test_kanban_goal_mode.py
      @@ -132,8 +132,6 @@ def _fake_popen(cmd, **kwargs):
               return _FakeProc()
       
           monkeypatch.setattr("subprocess.Popen", _fake_popen)
      -    # Avoid the kanban-worker skill probe touching the real skills dir.
      -    monkeypatch.setattr(kb, "_kanban_worker_skill_available", lambda home: False)
       
           with kb.connect() as conn:
               tid = kb.create_task(
      @@ -162,7 +160,6 @@ def _fake_popen(cmd, **kwargs):
               return _FakeProc()
       
           monkeypatch.setattr("subprocess.Popen", _fake_popen)
      -    monkeypatch.setattr(kb, "_kanban_worker_skill_available", lambda home: False)
       
           with kb.connect() as conn:
               tid = kb.create_task(conn, title="plain", assignee="default")
    • tests/tools/test_kanban_tools.py
      @@ -1224,8 +1224,16 @@ def test_kanban_guidance_in_worker_prompt(monkeypatch, tmp_path):
       
       
       def test_kanban_guidance_prompt_size_bounded(monkeypatch, tmp_path):
      -    """Sanity: the guidance block is under 4 KB so it doesn't blow
      -    up the cached prompt."""
      +    """Sanity: the guidance block stays lean so it doesn't blow up the
      +    cached prompt.
      +
      +    The ceiling guards against unbounded growth, not against any growth.
      +    The block absorbed the load-bearing worker/orchestrator reference
      +    details (workspace kinds, deliverable artifacts, created-card claims,
      +    profile discovery) when the standalone kanban-worker / kanban-orchestrator
      +    skills were removed and folded into this always-injected guidance, so the
      +    ceiling is sized to fit that content with a little headroom.
      +    """
           monkeypatch.setenv("HERMES_KANBAN_TASK", "t_fake")
           home = tmp_path / ".hermes"
           home.mkdir()
      @@ -1234,7 +1242,7 @@ def test_kanban_guidance_prompt_size_bounded(monkeypatch, tmp_path):
           monkeypatch.setattr(_P, "home", lambda: tmp_path)
       
           from agent.prompt_builder import KANBAN_GUIDANCE
      -    assert 1_500 < len(KANBAN_GUIDANCE) < 4_096, (
      +    assert 1_500 < len(KANBAN_GUIDANCE) < 5_500, (
               f"KANBAN_GUIDANCE is {len(KANBAN_GUIDANCE)} chars — too short (missing?) or too long"
           )
       
    • tools/kanban_tools.py
      @@ -1382,8 +1382,8 @@ def _board_schema_prop() -> dict[str, str]:
                       "items": {"type": "string"},
                       "description": (
                           "Skill names to force-load into the dispatched "
      -                    "worker (in addition to the built-in kanban-worker "
      -                    "skill). Use this to pin a task to a specialist "
      +                    "worker. The kanban lifecycle is already injected "
      +                    "automatically; use this to pin a task to a specialist "
                           "context — e.g. ['translation'] for a translation "
                           "task, ['github-code-review'] for a reviewer task. "
                           "The names must match skills installed on the "
    • website/docs/reference/skills-catalog.md
      @@ -62,8 +62,7 @@ If a skill is missing from this list but present in the repo, the catalog is reg
       
       | Skill | Description | Path |
       |-------|-------------|------|
      -| [`kanban-orchestrator`](/docs/user-guide/skills/bundled/devops/devops-kanban-orchestrator) | Decomposition playbook + anti-temptation rules for an orchestrator profile routing work through Kanban. The "don't do the work yourself" rule and the basic lifecycle are auto-injected into every kanban worker's system prompt; this skill... | `devops/kanban-orchestrator` |
      -| [`kanban-worker`](/docs/user-guide/skills/bundled/devops/devops-kanban-worker) | Pitfalls, examples, and edge cases for Hermes Kanban workers. The lifecycle itself is auto-injected into every worker's system prompt as KANBAN_GUIDANCE (from agent/prompt_builder.py); this skill is what you load when you want deeper det... | `devops/kanban-worker` |
      +
       
       ## dogfood
       
    • website/docs/user-guide/features/kanban-worker-lanes.md
      @@ -7,7 +7,7 @@ This page is the contract. It exists for two audiences:
       - **Operators** picking which lanes to wire into a board (which profiles to create, which assignees to use).
       - **Plugin / integration authors** wanting to add a new lane shape (a CLI worker that wraps Codex / Claude Code / OpenCode, a containerised review worker, a non-Hermes service that pulls tasks via the API).
       
      -If you're writing the worker code itself — the agent that runs *inside* a lane — the [`kanban-worker`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-worker/SKILL.md) skill is the deeper procedural detail.
      +If you're writing the worker code itself — the agent that runs *inside* a lane — the kanban lifecycle and reference details are injected into the worker's system prompt automatically (the `KANBAN_GUIDANCE` block in [`agent/prompt_builder.py`](https://github.com/NousResearch/hermes-agent/blob/main/agent/prompt_builder.py)).
       
       ## The hierarchy
       
      @@ -64,7 +64,7 @@ For most code-changing tasks, the work isn't truly *done* the moment the worker
       - **Drop structured metadata into a `kanban_comment` first** since `kanban_block` only carries the human-readable `reason`. Comments are the durable annotation channel — every audit-relevant field (changed_files, tests_run, diff_path or PR url, decisions) belongs there.
       - **Reviewer either approves and unblocks**, which respawns the worker with the comment thread for follow-ups; or asks for changes via another comment, which the next worker run sees as part of `kanban_show`'s context.
       
      -The [`kanban-worker`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-worker/SKILL.md) skill has worked examples for both `kanban_complete` (truly terminal tasks — typo fixes, docs changes, research writeups) and the `review-required` block pattern.
      +The injected `KANBAN_GUIDANCE` covers both `kanban_complete` (truly terminal tasks — typo fixes, docs changes, research writeups) and the `review-required` block pattern.
       
       ## Logs and audit trail
       
      @@ -80,9 +80,9 @@ The dashboard renders run history with summaries, metadata blocks, and exit-stat
       
       ### Hermes profile lane (default)
       
      -The shape every kanban worker takes today: the assignee is a profile name, the dispatcher spawns `hermes -p <profile>`, the worker auto-loads the [`kanban-worker`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-worker/SKILL.md) skill plus the `KANBAN_GUIDANCE` system-prompt block, and uses the `kanban_*` tools to terminate the run. No setup beyond defining the profile.
      +The shape every kanban worker takes today: the assignee is a profile name, the dispatcher spawns `hermes -p <profile>`, the worker gets the `KANBAN_GUIDANCE` system-prompt block injected automatically, and uses the `kanban_*` tools to terminate the run. No setup beyond defining the profile.
       
      -When you create profiles for your fleet, choose names that match the *role* you want the orchestrator to route to. The orchestrator (when there is one) discovers your profile names via `hermes profile list` — there's no fixed roster the system assumes (see the [`kanban-orchestrator`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-orchestrator/SKILL.md) skill for the orchestrator side of the contract).
      +When you create profiles for your fleet, choose names that match the *role* you want the orchestrator to route to. The orchestrator (when there is one) discovers your profile names via `hermes profile list` — there's no fixed roster the system assumes (the orchestrator side of the contract is part of the injected `KANBAN_GUIDANCE`).
       
       ### Orchestrator profile lane
       
      @@ -110,5 +110,4 @@ So lane authors don't have to reimplement these:
       
       - [Kanban overview](./kanban) — the user-facing intro.
       - [Kanban tutorial](./kanban-tutorial) — walkthrough with the dashboard open.
      -- [`kanban-worker`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-worker/SKILL.md) — the skill the worker process loads.
      -- [`kanban-orchestrator`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-orchestrator/SKILL.md) — the orchestrator side.
      +- [`KANBAN_GUIDANCE`](https://github.com/NousResearch/hermes-agent/blob/main/agent/prompt_builder.py) — the worker + orchestrator lifecycle injected into every kanban worker's system prompt.
    • website/docs/user-guide/features/kanban.md
      @@ -310,7 +310,7 @@ kanban_create(
       kanban_complete(summary="decomposed into 2 research tasks + 1 writer; linked dependencies")
       ```
       
      -The "(Orchestrators)" tools — `kanban_list`, `kanban_create`, `kanban_link`, `kanban_unblock`, and `kanban_comment` on foreign tasks — are available through the same toolset; the convention (enforced by the `kanban-orchestrator` skill) is that worker profiles don't fan out or route unrelated work, and orchestrator profiles don't execute implementation work. Dispatcher-spawned workers are still task-scoped for destructive lifecycle operations and cannot mutate unrelated tasks.
      +The "(Orchestrators)" tools — `kanban_list`, `kanban_create`, `kanban_link`, `kanban_unblock`, and `kanban_comment` on foreign tasks — are available through the same toolset; the convention (encoded in the auto-injected kanban guidance) is that worker profiles don't fan out or route unrelated work, and orchestrator profiles don't execute implementation work. Dispatcher-spawned workers are still task-scoped for destructive lifecycle operations and cannot mutate unrelated tasks.
       
       ### Why tools instead of shelling to `hermes kanban`
       
      @@ -322,7 +322,7 @@ Three reasons:
       
       **Zero schema footprint on normal sessions.** A regular `hermes chat` session has zero `kanban_*` tools in its schema unless the active profile explicitly enables the `kanban` toolset for orchestrator work. Dispatcher-spawned task workers get task-scoped tools because `HERMES_KANBAN_TASK` is set; orchestrator profiles get the broader routing surface through config. No tool bloat for users who never touch kanban.
       
      -The `kanban-worker` and `kanban-orchestrator` skills teach the model which tool to call when and in what order.
      +The auto-injected kanban guidance teaches the model which tool to call when and in what order.
       
       ### Recommended handoff evidence
       
      @@ -358,9 +358,9 @@ Keep secrets, raw logs, tokens, OAuth material, and unrelated transcripts out of
       tests, say so explicitly in `summary` and use `metadata` for the evidence that
       does exist, such as source URLs, issue ids, or manual review steps.
       
      -### The worker skill
      +### The worker lifecycle
       
      -Any profile that should be able to work kanban tasks must load the `kanban-worker` skill. It teaches the worker the full lifecycle in **tool calls**, not CLI commands:
      +Every profile that works kanban tasks automatically gets the worker lifecycle — it's injected into the worker's system prompt at spawn (the `KANBAN_GUIDANCE` block), so there is **nothing to install or configure**. It teaches the worker the full lifecycle in **tool calls**, not CLI commands:
       
       1. On spawn, call `kanban_show()` to read title + body + parent handoffs + prior attempts + full comment thread.
       2. `cd $HERMES_KANBAN_WORKSPACE` (via the terminal tool) and do the work there.
      @@ -374,22 +374,7 @@ protocol. If the worker process exits with status 0 while the task is still
       of respawning it into the same loop. This usually means the model wrote a
       plain-text answer and exited without using the Kanban tool surface.
       
      -`kanban-worker` is a bundled skill, synced into every profile during install and
      -update — there is no separate Skills Hub install step. Verify it is present in
      -whichever profile you use for kanban workers (`researcher`, `writer`, `ops`,
      -etc.):
      -
      -```bash
      -hermes -p <your-worker-profile> skills list | grep kanban-worker
      -```
      -
      -If the bundled copy is missing, restore it for that profile:
      -
      -```bash
      -hermes -p <your-worker-profile> skills reset kanban-worker --restore
      -```
      -
      -The dispatcher also auto-passes `--skills kanban-worker` when spawning every worker, so the worker always has the pattern library available even if a profile's default skills config doesn't include it.
      +The lifecycle plus the load-bearing reference details (workspace kinds, deliverable `artifacts`, claiming created cards) ship in that system-prompt block, so every worker has them regardless of which profile it runs under — no per-profile skill setup required.
       
       ### Pinning extra skills to a specific task
       
      @@ -426,7 +411,7 @@ hermes kanban create "audit auth flow" \
       
       **From the dashboard**, type the skills comma-separated into the **skills** field of the inline create form.
       
      -These skills are **additive** to the built-in `kanban-worker` — the dispatcher emits one `--skills <name>` flag for each (and for the built-in), so the worker spawns with all of them loaded. The skill names must match skills that are actually installed on the assignee's profile (run `hermes skills list` to see what's available); there's no runtime install.
      +The dispatcher emits one `--skills <name>` flag per skill listed, so the worker spawns with all of them loaded on top of the auto-injected kanban guidance. The skill names must match skills that are actually installed on the assignee's profile (run `hermes skills list` to see what's available); there's no runtime install.
       
       ### Goal-mode cards (`--goal`)
       
      @@ -442,9 +427,9 @@ hermes kanban create "Translate the docs site to French" \
       
       Use it for open-ended, multi-step, or "keep going until X is true" cards. Skip it for cheap one-shot work — the per-turn judge overhead isn't worth it, and the dispatcher's existing retry/circuit-breaker already handles transient worker failures. The judge is only as good as your goal text, so write the body as **explicit acceptance criteria**.
       
      -### The orchestrator skill
      +### How the orchestrator behaves
       
      -A **well-behaved orchestrator does not do the work itself.** It decomposes the user's goal into tasks, links them, assigns each to one of the profiles you've set up, and steps back. The `kanban-orchestrator` skill encodes this as tool-call patterns: anti-temptation rules, a Step-0 profile-discovery prompt (the dispatcher silently fails on unknown assignee names, so the orchestrator must ground every card in profiles that actually exist on your machine), and a decomposition playbook keyed on `kanban_create` / `kanban_link` / `kanban_comment`.
      +A **well-behaved orchestrator does not do the work itself.** It decomposes the user's goal into tasks, links them, assigns each to one of the profiles you've set up, and steps back. The orchestrator guidance — anti-temptation rules, a Step-0 profile-discovery prompt (the dispatcher silently fails on unknown assignee names, so the orchestrator must ground every card in profiles that actually exist on your machine), and a decomposition playbook keyed on `kanban_create` / `kanban_link` / `kanban_comment` — is injected into the worker's system prompt automatically; there is nothing to install.
       
       A canonical orchestrator turn (two parallel researchers handing off to a writer):
       
      @@ -465,19 +450,7 @@ kanban_complete(
       )
       ```
       
      -`kanban-orchestrator` is a bundled skill. It is synced into each profile during
      -install and update, so there is no separate Skills Hub install step. Verify it is
      -present in your orchestrator profile:
      -
      -```bash
      -hermes -p orchestrator skills list | grep kanban-orchestrator
      -```
      -
      -If the bundled copy is missing, restore it for that profile:
      -
      -```bash
      -hermes -p orchestrator skills reset kanban-orchestrator --restore
      -```
      +The orchestrator guidance ships in the worker's system prompt automatically — there is nothing to install or sync per profile.
       
       For best results, pair it with a profile whose toolsets are restricted to board operations (`kanban`, `gateway`, `memory`) so the orchestrator literally cannot execute implementation tasks even if it tries.
       
    • website/docs/user-guide/skills/bundled/autonomous-ai-agents/autonomous-ai-agents-kanban-codex-lane.md
      @@ -20,7 +20,7 @@ Use when a Hermes Kanban worker wants to run Codex CLI as an isolated implementa
       | Author | Hermes Agent |
       | License | MIT |
       | Tags | `kanban`, `codex`, `worktrees`, `autonomous-agents`, `prediction-market-bot` |
      -| Related skills | [`kanban-worker`](/docs/user-guide/skills/bundled/devops/devops-kanban-worker), [`codex`](/docs/user-guide/skills/bundled/autonomous-ai-agents/autonomous-ai-agents-codex), [`hermes-agent`](/docs/user-guide/skills/bundled/autonomous-ai-agents/autonomous-ai-agents-hermes-agent) |
      +| Related skills | [`codex`](/docs/user-guide/skills/bundled/autonomous-ai-agents/autonomous-ai-agents-codex), [`hermes-agent`](/docs/user-guide/skills/bundled/autonomous-ai-agents/autonomous-ai-agents-hermes-agent) |
       
       ## Reference: full SKILL.md
       
    • /dev/null
      @@ -1,231 +0,0 @@
      ----
      -title: "Kanban Orchestrator"
      -sidebar_label: "Kanban Orchestrator"
      -description: "Decomposition playbook + anti-temptation rules for an orchestrator profile routing work through Kanban"
      ----
      -
      -{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
      -
      -# Kanban Orchestrator
      -
      -Decomposition playbook + anti-temptation rules for an orchestrator profile routing work through Kanban. The "don't do the work yourself" rule and the basic lifecycle are auto-injected into every kanban worker's system prompt; this skill is the deeper playbook when you're specifically playing the orchestrator role.
      -
      -## Skill metadata
      -
      -| | |
      -|---|---|
      -| Source | Bundled (installed by default) |
      -| Path | `skills/devops/kanban-orchestrator` |
      -| Version | `3.0.0` |
      -| Platforms | linux, macos, windows |
      -| Tags | `kanban`, `multi-agent`, `orchestration`, `routing` |
      -| Related skills | [`kanban-worker`](/docs/user-guide/skills/bundled/devops/devops-kanban-worker) |
      -
      -## Reference: full SKILL.md
      -
      -:::info
      -The following is the complete skill definition that Hermes loads when this skill is triggered. This is what the agent sees as instructions when the skill is active.
      -:::
      -
      -# Kanban Orchestrator — Decomposition Playbook
      -
      -> The **core worker lifecycle** (including the `kanban_create` fan-out pattern and the "decompose, don't execute" rule) is auto-injected into every kanban process via the `KANBAN_GUIDANCE` system-prompt block. This skill is the deeper playbook when you're an orchestrator profile whose whole job is routing.
      -
      -## Profiles are user-configured — not a fixed roster
      -
      -Hermes setups vary widely. Some users run a single profile that does everything; some run a small fleet (`docker-worker`, `cron-worker`); some run a curated specialist team they've named themselves. There is **no default specialist roster** — the orchestrator skill does not know what profiles exist on this machine.
      -
      -Before fanning out, you must ground the decomposition in the profiles that actually exist. The dispatcher silently fails to spawn unknown assignee names — it doesn't autocorrect, doesn't suggest, doesn't fall back. So a card assigned to `researcher` on a setup that only has `docker-worker` just sits in `ready` forever.
      -
      -**Step 0: discover available profiles before planning.**
      -
      -Use one of these:
      -
      -- `hermes profile list` — prints the table of profiles configured on this machine. Run it through your terminal tool if you have one; otherwise ask the user.
      -- `kanban_list(assignee="<some-name>")` — sanity-check a single name. Returns an empty list (rather than an error) for an unknown assignee, so this only confirms a name you're already considering.
      -- **Just ask the user.** "What profiles do you have set up?" is a fine first turn when the goal needs more than one specialist.
      -
      -Cache the result in your working memory for the rest of the conversation. Re-asking every turn wastes a tool call.
      -
      -## When to use the board (vs. just doing the work)
      -
      -Create Kanban tasks when any of these are true:
      -
      -1. **Multiple specialists are needed.** Research + analysis + writing is three profiles.
      -2. **The work should survive a crash or restart.** Long-running, recurring, or important.
      -3. **The user might want to interject.** Human-in-the-loop at any step.
      -4. **Multiple subtasks can run in parallel.** Fan-out for speed.
      -5. **Review / iteration is expected.** A reviewer profile loops on drafter output.
      -6. **The audit trail matters.** Board rows persist in SQLite forever.
      -
      -If *none* of those apply — it's a small one-shot reasoning task — use `delegate_task` instead or answer the user directly.
      -
      -## The anti-temptation rules
      -
      -Your job description says "route, don't execute." The rules that enforce that:
      -
      -- **Do not execute the work yourself.** Your restricted toolset usually doesn't even include terminal/file/code/web for implementation. If you find yourself "just fixing this quickly" — stop and create a task for the right specialist.
      -- **For any concrete task, create a Kanban task and assign it.** Every single time.
      -- **Split multi-lane requests before creating cards.** A user prompt can contain several independent workstreams. Extract those lanes first, then create one card per lane instead of bundling unrelated work into a single implementer card.
      -- **Run independent lanes in parallel.** If two cards do not need each other's output, leave them unlinked so the dispatcher can fan them out. Link only true data dependencies.
      -- **Never create dependent work as independent ready cards.** If a card must wait for another card, pass `parents=[...]` in the original `kanban_create` call. Do not create it first and link it later, and do not rely on prose like "wait for T1" inside the body.
      -- **If no specialist fits the available profiles, ask the user which profile to create or which existing profile to use.** Do not invent profile names; the dispatcher will silently drop unknown assignees.
      -- **Decompose, route, and summarize — that's the whole job.**
      -
      -## Decomposition playbook
      -
      -### Step 1 — Understand the goal
      -
      -Ask clarifying questions if the goal is ambiguous. Cheap to ask; expensive to spawn the wrong fleet.
      -
      -### Step 2 — Sketch the task graph
      -
      -Before creating anything, draft the graph out loud (in your response to the user). Treat every concrete workstream as a candidate card:
      -
      -1. Extract the lanes from the request.
      -2. Map each lane to one of the profiles you discovered in Step 0. If a lane doesn't fit any existing profile, ask the user which to use or create.
      -3. Decide whether each lane is independent or gated by another lane.
      -4. Create independent lanes as parallel cards with no parent links.
      -5. Create synthesis/review/integration cards with parent links to the lanes they depend on. A child created with unfinished parents starts in `todo`; the dispatcher promotes it to `ready` only after every parent is done.
      -
      -Examples of prompts that should fan out (using placeholder profile names — substitute whatever exists on the user's setup):
      -
      -- "Build an app" → one card to a design-oriented profile for product/UI direction, one or two cards to engineering profiles for implementation, plus a later integration/review card if the user has a reviewer profile.
      -- "Fix blockers and check model variants" → one implementation card for the blocker fixes plus one discovery/research card for config/source verification. A final reviewer card can depend on both.
      -- "Research docs and implement" → a docs-research card can run in parallel with a codebase-discovery card; implementation waits only if it truly needs those findings.
      -- "Analyze this screenshot and find the related code" → one card to a vision-capable profile for the visual analysis while another searches the codebase.
      -
      -Words like "also," "finally," or "and" do not automatically imply a dependency. They often mean "make sure this is covered before reporting back." Only link tasks when one card cannot start until another card's output exists.
      -
      -Show the graph to the user before creating cards. Let them correct it — including which actual profile name should own each lane.
      -
      -### Step 3 — Create tasks and link
      -
      -Use the profile names from Step 0. The example below uses placeholders `<profile-A>`, `<profile-B>`, `<profile-C>` — replace them with what the user actually has.
      -
      -```python
      -t1 = kanban_create(
      -    title="research: Postgres cost vs current",
      -    assignee="<profile-A>",  # whichever profile handles research on this setup
      -    body="Compare estimated infrastructure costs, migration costs, and ongoing ops costs over a 3-year window. Sources: AWS/GCP pricing, team time estimates, current Postgres bills from peers.",
      -    tenant=os.environ.get("HERMES_TENANT"),
      -)["task_id"]
      -
      -t2 = kanban_create(
      -    title="research: Postgres performance vs current",
      -    assignee="<profile-A>",  # same profile, run in parallel
      -    body="Compare query latency, throughput, and scaling characteristics at our expected data volume (~500GB, 10k QPS peak). Sources: benchmark papers, public case studies, pgbench results if easy.",
      -)["task_id"]
      -
      -t3 = kanban_create(
      -    title="synthesize migration recommendation",
      -    assignee="<profile-B>",  # whichever profile does synthesis/analysis
      -    body="Read the findings from T1 (cost) and T2 (performance). Produce a 1-page recommendation with explicit trade-offs and a go/no-go call.",
      -    parents=[t1, t2],
      -)["task_id"]
      -
      -t4 = kanban_create(
      -    title="draft decision memo",
      -    assignee="<profile-C>",  # whichever profile drafts user-facing prose
      -    body="Turn the analyst's recommendation into a 2-page memo for the CTO. Match the tone of previous decision memos in the team's knowledge base.",
      -    parents=[t3],
      -)["task_id"]
      -```
      -
      -`parents=[...]` gates promotion — children stay in `todo` until every parent reaches `done`, then auto-promote to `ready`. No manual coordination needed; the dispatcher and dependency engine handle it.
      -
      -If the task graph has dependencies, create the parent cards first, capture their returned ids, and include those ids in the child card's `parents` list during the child `kanban_create` call. Avoid creating all cards in parallel and linking them afterward; that creates a window where the dispatcher can claim a child before its inputs exist.
      -
      -### Step 4 — Complete your own task
      -
      -If you were spawned as a task yourself (e.g. a planner profile was assigned `T0: "investigate Postgres migration"`), mark it done with a summary of what you created:
      -
      -```python
      -kanban_complete(
      -    summary="decomposed into T1-T4: 2 research lanes in parallel, 1 synthesis on their outputs, 1 prose draft on the recommendation",
      -    metadata={
      -        "task_graph": {
      -            "T1": {"assignee": "<profile-A>", "parents": []},
      -            "T2": {"assignee": "<profile-A>", "parents": []},
      -            "T3": {"assignee": "<profile-B>", "parents": ["T1", "T2"]},
      -            "T4": {"assignee": "<profile-C>", "parents": ["T3"]},
      -        },
      -    },
      -)
      -```
      -
      -### Step 5 — Report back to the user
      -
      -Tell them what you created in plain prose, naming the actual profiles you used:
      -
      -> I've queued 4 tasks:
      -> - **T1** (`<profile-A>`): cost comparison
      -> - **T2** (`<profile-A>`): performance comparison, in parallel with T1
      -> - **T3** (`<profile-B>`): synthesizes T1 + T2 into a recommendation
      -> - **T4** (`<profile-C>`): turns T3 into a CTO memo
      ->
      -> The dispatcher will pick up T1 and T2 now. T3 starts when both finish. You'll get a gateway ping when T4 completes. Use the dashboard or `hermes kanban tail <id>` to follow along.
      -
      -## Common patterns
      -
      -**Fan-out + fan-in (research → synthesize):** N research-style cards with no parents, one synthesis card with all of them as parents.
      -
      -**Parallel implementation + validation:** one implementer card makes the change while one explorer/researcher card verifies config, docs, or source mapping. A reviewer card can depend on both. Do not make the implementer own unrelated verification just because the user mentioned both in one sentence.
      -
      -**Pipeline with gates:** `planner → implementer → reviewer`. Each stage's `parents=[previous_task]`. Reviewer blocks or completes; if reviewer blocks, the operator unblocks with feedback and respawns.
      -
      -**Same-profile queue:** N tasks, all assigned to the same profile, no dependencies between them. Dispatcher serializes — that profile processes them in priority order, accumulating experience in its own memory.
      -
      -**Human-in-the-loop:** Any task can `kanban_block()` to wait for input. Dispatcher respawns after `/unblock`. The comment thread carries the full context.
      -
      -## Pitfalls
      -
      -**Inventing profile names that don't exist.** The dispatcher silently fails to spawn unknown assignees — the card just sits in `ready` forever. Always assign to a profile from your Step 0 discovery; ask the user if you're unsure.
      -
      -**Bundling independent lanes into one card.** If the user asks for two independent outcomes, create two cards. Example: "fix blockers and check model variants" is not one fixer task; create a fixer/engineer card for the fixes and an explorer/researcher card for the variant check, then optionally gate review on both.
      -
      -**Over-linking because of wording.** "Finally check X" may still be parallel with implementation if X is static config, docs, or source discovery. Link it after implementation only when the check depends on the implementation result.
      -
      -**Forgetting dependency links.** If the task graph says `research -> implement -> review`, do not create all tasks as independent ready cards. Use parent links so implement/review cannot run before their inputs exist.
      -
      -**Reassignment vs. new task.** If a reviewer blocks with "needs changes," create a NEW task linked from the reviewer's task — don't re-run the same task with a stern look. The new task is assigned to the original implementer profile.
      -
      -**Argument order for links.** `kanban_link(parent_id=..., child_id=...)` — parent first. Mixing them up demotes the wrong task to `todo`.
      -
      -**Don't pre-create the whole graph if the shape depends on intermediate findings.** If T3's structure depends on what T1 and T2 find, let T3 exist as a "synthesize findings" task whose own first step is to read parent handoffs and plan the rest. Orchestrators can spawn orchestrators.
      -
      -**Tenant inheritance.** If `HERMES_TENANT` is set in your env, pass `tenant=os.environ.get("HERMES_TENANT")` on every `kanban_create` call so child tasks stay in the same namespace.
      -
      -## Goal-mode cards (persistent workers)
      -
      -By default a dispatched worker gets **one shot** at its card: it does its work, calls `kanban_complete`/`kanban_block`, and exits. For open-ended cards where one turn rarely finishes the job, pass `goal_mode=True` to wrap that worker in a Ralph-style goal loop — the same engine behind the `/goal` slash command:
      -
      -```python
      -kanban_create(
      -    title="Translate the full docs site to French",
      -    body="Acceptance: every page translated, no English left, links intact.",
      -    assignee="<translator-profile>",
      -    goal_mode=True,        # judge re-checks the card after each turn
      -    goal_max_turns=15,     # optional budget (default 20)
      -)["task_id"]
      -```
      -
      -How it behaves:
      -- After each worker turn, an auxiliary judge evaluates the worker's response against the card's **title + body** (treated as the acceptance criteria).
      -- Not done + budget remains → the worker keeps going **in the same session** (full context retained — not a fresh respawn).
      -- Worker calls `kanban_complete`/`kanban_block` itself → loop stops, normal lifecycle.
      -- Budget exhausted without completion → the card is **blocked** for human review (sticky), never a silent exit.
      -
      -When to use it: long, multi-step, or "keep going until X is true" cards. When NOT to: cheap one-shot cards (translation of a single string, a quick lookup) — the judge overhead isn't worth it, and the dispatcher's existing retry/circuit-breaker already handles transient worker failures.
      -
      -Write the body as **explicit acceptance criteria** — the judge is only as good as the goal text. "Translate the README" is weaker than "Translate every section of the README to French; no English sentences remain."
      -
      -## Recovering stuck workers
      -
      -When a worker profile keeps crashing, hallucinating, or getting blocked by its own mistakes (usually: wrong model, missing skill, broken credential), the kanban dashboard flags the task with a ⚠ badge and opens a **Recovery** section in the drawer. Three primary actions:
      -
      -1. **Reclaim** (or `hermes kanban reclaim <task_id>`) — abort the running worker immediately and reset the task to `ready`. The existing claim TTL is ~15 min; this is the fast path out.
      -2. **Reassign** (or `hermes kanban reassign <task_id> <new-profile> --reclaim`) — switch the task to a different profile (one that exists on this setup) and let the dispatcher pick it up with a fresh worker.
      -3. **Change profile model** — the dashboard prints a copy-paste hint for `hermes -p <profile> model` since profile config lives on disk; edit it in a terminal, then Reclaim to retry with the new model.
      -
      -Hallucination warnings appear on tasks where a worker's `kanban_complete(created_cards=[...])` claim included card ids that don't exist or weren't created by the worker's profile (the gate blocks the completion), or where the free-form summary references `t_<hex>` ids that don't resolve (advisory prose scan, non-blocking). Both produce audit events that persist even after recovery actions — the trail stays for debugging.
    • /dev/null
      @@ -1,210 +0,0 @@
      ----
      -title: "Kanban Worker — Pitfalls, examples, and edge cases for Hermes Kanban workers"
      -sidebar_label: "Kanban Worker"
      -description: "Pitfalls, examples, and edge cases for Hermes Kanban workers"
      ----
      -
      -{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
      -
      -# Kanban Worker
      -
      -Pitfalls, examples, and edge cases for Hermes Kanban workers. The lifecycle itself is auto-injected into every worker's system prompt as KANBAN_GUIDANCE (from agent/prompt_builder.py); this skill is what you load when you want deeper detail on specific scenarios.
      -
      -## Skill metadata
      -
      -| | |
      -|---|---|
      -| Source | Bundled (installed by default) |
      -| Path | `skills/devops/kanban-worker` |
      -| Version | `2.0.0` |
      -| Platforms | linux, macos, windows |
      -| Tags | `kanban`, `multi-agent`, `collaboration`, `workflow`, `pitfalls` |
      -| Related skills | [`kanban-orchestrator`](/docs/user-guide/skills/bundled/devops/devops-kanban-orchestrator) |
      -
      -## Reference: full SKILL.md
      -
      -:::info
      -The following is the complete skill definition that Hermes loads when this skill is triggered. This is what the agent sees as instructions when the skill is active.
      -:::
      -
      -# Kanban Worker — Pitfalls and Examples
      -
      -> You're seeing this skill because the Hermes Kanban dispatcher spawned you as a worker with `--skills kanban-worker` — it's loaded automatically for every dispatched worker. The **lifecycle** (6 steps: orient → work → heartbeat → block/complete) also lives in the `KANBAN_GUIDANCE` block that's auto-injected into your system prompt. This skill is the deeper detail: good handoff shapes, retry diagnostics, edge cases.
      -
      -## Workspace handling
      -
      -Your workspace kind determines how you should behave inside `$HERMES_KANBAN_WORKSPACE`:
      -
      -| Kind | What it is | How to work |
      -|---|---|---|
      -| `scratch` | Fresh tmp dir, yours alone | Read/write freely; it gets GC'd when the task is archived. |
      -| `dir:<path>` | Shared persistent directory | Other runs will read what you write. Treat it like long-lived state. Path is guaranteed absolute (the kernel rejects relative paths). |
      -| `worktree` | Git worktree at the resolved path | If `.git` doesn't exist, run `git worktree add <path> ${HERMES_KANBAN_BRANCH:-wt/$HERMES_KANBAN_TASK}` from the main repo first, then cd and work normally. Commit work here. |
      -
      -## Tenant isolation
      -
      -If `$HERMES_TENANT` is set, the task belongs to a tenant namespace. When reading or writing persistent memory, prefix memory entries with the tenant so context doesn't leak across tenants:
      -
      -- Good: `business-a: Acme is our biggest customer`
      -- Bad (leaks): `Acme is our biggest customer`
      -
      -## Good summary + metadata shapes
      -
      -The `kanban_complete(summary=..., metadata=...)` handoff is how downstream workers read what you did. Patterns that work:
      -
      -**Coding task:**
      -```python
      -kanban_complete(
      -    summary="shipped rate limiter — token bucket, keys on user_id with IP fallback, 14 tests pass",
      -    metadata={
      -        "changed_files": ["rate_limiter.py", "tests/test_rate_limiter.py"],
      -        "tests_run": 14,
      -        "tests_passed": 14,
      -        "decisions": ["user_id primary, IP fallback for unauthenticated requests"],
      -    },
      -)
      -```
      -
      -**Coding task that needs human review (review-required):**
      -
      -For most code-changing tasks, the work isn't truly *done* until a human reviewer has eyes on it. Block instead of complete, with `reason` prefixed `review-required: ` so the dashboard surfaces the row as needing review. Drop the structured metadata (changed files, test counts, diff/PR url) into a comment first, since `kanban_block` only carries the human-readable reason — comments are the durable annotation channel. Reviewer either approves and runs `hermes kanban unblock <id>` (which re-spawns you with the comment thread for any follow-ups) or asks for changes via another comment.
      -
      -```python
      -import json
      -
      -kanban_comment(
      -    body="review-required handoff:\n" + json.dumps({
      -        "changed_files": ["rate_limiter.py", "tests/test_rate_limiter.py"],
      -        "tests_run": 14,
      -        "tests_passed": 14,
      -        "diff_path": "/path/to/worktree",  # or PR url if pushed
      -        "decisions": ["user_id primary, IP fallback for unauthenticated requests"],
      -    }, indent=2),
      -)
      -kanban_block(
      -    reason="review-required: rate limiter shipped, 14/14 tests pass — needs eyes on the user_id/IP fallback choice before merging",
      -)
      -```
      -
      -Use `kanban_complete` only when the task is genuinely terminal — e.g. a one-line typo fix, a docs change with no functional consequences, or a research task where the artifact IS the writeup itself.
      -
      -**Research task:**
      -```python
      -kanban_complete(
      -    summary="3 competing libraries reviewed; vLLM wins on throughput, SGLang on latency, Tensorrt-LLM on memory efficiency",
      -    metadata={
      -        "sources_read": 12,
      -        "recommendation": "vLLM",
      -        "benchmarks": {"vllm": 1.0, "sglang": 0.87, "trtllm": 0.72},
      -    },
      -)
      -```
      -
      -**Review task:**
      -```python
      -kanban_complete(
      -    summary="reviewed PR #123; 2 blocking issues found (SQL injection in /search, missing CSRF on /settings)",
      -    metadata={
      -        "pr_number": 123,
      -        "findings": [
      -            {"severity": "critical", "file": "api/search.py", "line": 42, "issue": "raw SQL concat"},
      -            {"severity": "high", "file": "api/settings.py", "issue": "missing CSRF middleware"},
      -        ],
      -        "approved": False,
      -    },
      -)
      -```
      -
      -Shape `metadata` so downstream parsers (reviewers, aggregators, schedulers) can use it without re-reading your prose.
      -
      -## Claiming cards you actually created
      -
      -If your run produced new kanban tasks (via `kanban_create`), pass the ids in `created_cards` on `kanban_complete`. The kernel verifies each id exists and was created by your profile; any phantom id blocks the completion with an error listing what went wrong, and the rejected attempt is permanently recorded on the task's event log. **Only list ids you captured from a successful `kanban_create` return value — never invent ids from prose, never paste ids from earlier runs, never claim cards another worker created.**
      -
      -```python
      -# GOOD — capture return values, then claim them.
      -c1 = kanban_create(title="remediate SQL injection", assignee="security-worker")
      -c2 = kanban_create(title="fix CSRF middleware", assignee="web-worker")
      -
      -kanban_complete(
      -    summary="Review done; spawned remediations for both findings.",
      -    metadata={"pr_number": 123, "approved": False},
      -    created_cards=[c1["task_id"], c2["task_id"]],
      -)
      -```
      -
      -```python
      -# BAD — claiming ids you don't have captured return values for.
      -kanban_complete(
      -    summary="Created remediation cards t_a1b2c3d4, t_deadbeef",  # hallucinated
      -    created_cards=["t_a1b2c3d4", "t_deadbeef"],                   # → gate rejects
      -)
      -```
      -
      -If a `kanban_create` call fails (exception, tool_error), the card was NOT created — do not include a phantom id for it. Retry the create, or omit the id and mention the failure in your summary. The prose-scan pass also catches `t_<hex>` references in your free-form summary that don't resolve; these don't block the completion but show up as advisory warnings on the task in the dashboard.
      -
      -## Block reasons that get answered fast
      -
      -Bad: `"stuck"` — the human has no context.
      -
      -Good: one sentence naming the specific decision you need. Leave longer context as a comment instead.
      -
      -```python
      -kanban_comment(
      -    task_id=os.environ["HERMES_KANBAN_TASK"],
      -    body="Full context: I have user IPs from Cloudflare headers but some users are behind NATs with thousands of peers. Keying on IP alone causes false positives.",
      -)
      -kanban_block(reason="Rate limit key choice: IP (simple, NAT-unsafe) or user_id (requires auth, skips anonymous endpoints)?")
      -```
      -
      -The block message is what appears in the dashboard / gateway notifier. The comment is the deeper context a human reads when they open the task.
      -
      -## Heartbeats worth sending
      -
      -Good heartbeats name progress: `"epoch 12/50, loss 0.31"`, `"scanned 1.2M/2.4M rows"`, `"uploaded 47/120 videos"`.
      -
      -Bad heartbeats: `"still working"`, empty notes, sub-second intervals. Every few minutes max; skip entirely for tasks under ~2 minutes.
      -
      -## Retry scenarios
      -
      -If you open the task and `kanban_show` returns `runs: [...]` with one or more closed runs, you're a retry. The prior runs' `outcome` / `summary` / `error` tell you what didn't work. Don't repeat that path. Typical retry diagnostics:
      -
      -- `outcome: "timed_out"` — the previous attempt hit `max_runtime_seconds`. You may need to chunk the work or shorten it.
      -- `outcome: "crashed"` — OOM or segfault. Reduce memory footprint.
      -- `outcome: "spawn_failed"` + `error: "..."` — usually a profile config issue (missing credential, bad PATH). Ask the human via `kanban_block` instead of retrying blindly.
      -- `outcome: "reclaimed"` + `summary: "task archived..."` — operator archived the task out from under the previous run; you probably shouldn't be running at all, check status carefully.
      -- `outcome: "blocked"` — a previous attempt blocked; the unblock comment should be in the thread by now.
      -
      -## Notification routing
      -
      -You can configure the gateway to receive cross-profile Kanban task notifications by adding `notification_sources` to `~/.hermes/config.yaml`.
      -- `notification_sources: ['*']` accepts subscriptions from all profiles.
      -- `notification_sources: ['default', 'zilor-ppt']` or `"default,zilor-ppt"` restricts subscriptions to specified profiles.
      -- Omitting the key keeps the default behavior (profile isolation).
      -
      -## Do NOT
      -
      -- Call `delegate_task` as a substitute for `kanban_create`. `delegate_task` is for short reasoning subtasks inside YOUR run; `kanban_create` is for cross-agent handoffs that outlive one API loop.
      -- Call `clarify` to ask the human a question. You are running headless — there is no live user to answer. The call will time out (default ~120s) and the task will sit silently in `running` with no signal that it needs input. Use `kanban_comment` (context) + `kanban_block(reason=...)` (decision needed) instead — the task surfaces on the board as blocked, the operator sees it, unblocks with their answer in a comment, and you respawn with the thread.
      -- Modify files outside `$HERMES_KANBAN_WORKSPACE` unless the task body says to.
      -- Create follow-up tasks assigned to yourself — assign to the right specialist.
      -- Complete a task you didn't actually finish. Block it instead.
      -
      -## Pitfalls
      -
      -**Task state can change between dispatch and your startup.** Between when the dispatcher claimed and when your process actually booted, the task may have been blocked, reassigned, or archived. Always `kanban_show` first. If it reports `blocked` or `archived`, stop — you shouldn't be running.
      -
      -**Workspace may have stale artifacts.** Especially `dir:` and `worktree` workspaces can have files from previous runs. Read the comment thread — it usually explains why you're running again and what state the workspace is in.
      -
      -**Don't rely on the CLI when the guidance is available.** The `kanban_*` tools work across all terminal backends (Docker, Modal, SSH). `hermes kanban <verb>` from your terminal tool will fail in containerized backends because the CLI isn't installed there. When in doubt, use the tool.
      -
      -## CLI fallback (for scripting)
      -
      -Every tool has a CLI equivalent for human operators and scripts:
      -- `kanban_show` ↔ `hermes kanban show <id> --json`
      -- `kanban_complete` ↔ `hermes kanban complete <id> --summary "..." --metadata '{...}'`
      -- `kanban_block` ↔ `hermes kanban block <id> "reason"`
      -- `kanban_create` ↔ `hermes kanban create "title" --assignee <profile> [--parent <id>]`
      -- etc.
      -
      -Use the tools from inside an agent; the CLI exists for the human at the terminal.
    • website/docs/user-guide/skills/optional/creative/creative-kanban-video-orchestrator.md
      @@ -21,7 +21,7 @@ Plan, set up, and monitor a multi-agent video production pipeline backed by Herm
       | License | MIT |
       | Platforms | linux, macos, windows |
       | Tags | `video`, `kanban`, `multi-agent`, `orchestration`, `production-pipeline` |
      -| Related skills | [`kanban-orchestrator`](/docs/user-guide/skills/bundled/devops/devops-kanban-orchestrator), [`kanban-worker`](/docs/user-guide/skills/bundled/devops/devops-kanban-worker), [`ascii-video`](/docs/user-guide/skills/bundled/creative/creative-ascii-video), [`manim-video`](/docs/user-guide/skills/bundled/creative/creative-manim-video), [`p5js`](/docs/user-guide/skills/bundled/creative/creative-p5js), [`comfyui`](/docs/user-guide/skills/bundled/creative/creative-comfyui), [`touchdesigner-mcp`](/docs/user-guide/skills/bundled/creative/creative-touchdesigner-mcp), [`blender-mcp`](/docs/user-guide/skills/optional/creative/creative-blender-mcp), [`pixel-art`](/docs/user-guide/skills/optional/creative/creative-pixel-art), [`ascii-art`](/docs/user-guide/skills/bundled/creative/creative-ascii-art), [`songwriting-and-ai-music`](/docs/user-guide/skills/bundled/creative/creative-songwriting-and-ai-music), [`heartmula`](/docs/user-guide/skills/bundled/media/media-heartmula), [`songsee`](/docs/user-guide/skills/bundled/media/media-songsee), `spotify`, [`youtube-content`](/docs/user-guide/skills/bundled/media/media-youtube-content), [`claude-design`](/docs/user-guide/skills/bundled/creative/creative-claude-design), [`excalidraw`](/docs/user-guide/skills/bundled/creative/creative-excalidraw), [`architecture-diagram`](/docs/user-guide/skills/bundled/creative/creative-architecture-diagram), [`concept-diagrams`](/docs/user-guide/skills/optional/creative/creative-concept-diagrams), [`baoyu-comic`](/docs/user-guide/skills/optional/creative/creative-baoyu-comic), [`baoyu-infographic`](/docs/user-guide/skills/bundled/creative/creative-baoyu-infographic), [`humanizer`](/docs/user-guide/skills/bundled/creative/creative-humanizer), [`gif-search`](/docs/user-guide/skills/bundled/media/media-gif-search), [`meme-generation`](/docs/user-guide/skills/optional/creative/creative-meme-generation) |
      +| Related skills | [`ascii-video`](/docs/user-guide/skills/bundled/creative/creative-ascii-video), [`manim-video`](/docs/user-guide/skills/bundled/creative/creative-manim-video), [`p5js`](/docs/user-guide/skills/bundled/creative/creative-p5js), [`comfyui`](/docs/user-guide/skills/bundled/creative/creative-comfyui), [`touchdesigner-mcp`](/docs/user-guide/skills/bundled/creative/creative-touchdesigner-mcp), [`blender-mcp`](/docs/user-guide/skills/optional/creative/creative-blender-mcp), [`pixel-art`](/docs/user-guide/skills/optional/creative/creative-pixel-art), [`ascii-art`](/docs/user-guide/skills/bundled/creative/creative-ascii-art), [`songwriting-and-ai-music`](/docs/user-guide/skills/bundled/creative/creative-songwriting-and-ai-music), [`heartmula`](/docs/user-guide/skills/bundled/media/media-heartmula), [`songsee`](/docs/user-guide/skills/bundled/media/media-songsee), `spotify`, [`youtube-content`](/docs/user-guide/skills/bundled/media/media-youtube-content), [`claude-design`](/docs/user-guide/skills/bundled/creative/creative-claude-design), [`excalidraw`](/docs/user-guide/skills/bundled/creative/creative-excalidraw), [`architecture-diagram`](/docs/user-guide/skills/bundled/creative/creative-architecture-diagram), [`concept-diagrams`](/docs/user-guide/skills/optional/creative/creative-concept-diagrams), [`baoyu-comic`](/docs/user-guide/skills/optional/creative/creative-baoyu-comic), [`baoyu-infographic`](/docs/user-guide/skills/bundled/creative/creative-baoyu-infographic), [`humanizer`](/docs/user-guide/skills/bundled/creative/creative-humanizer), [`gif-search`](/docs/user-guide/skills/bundled/media/media-gif-search), [`meme-generation`](/docs/user-guide/skills/optional/creative/creative-meme-generation) |
       
       ## Reference: full SKILL.md
       
      @@ -187,7 +187,7 @@ task graphs. See **[references/examples.md](https://github.com/NousResearch/herm
          file` toolset, the director's `SOUL.md` rules forbid it from executing
          work itself. It decomposes and routes only — every concrete task becomes
          a `hermes kanban create` call to a specialist profile. The
      -   `kanban-orchestrator` skill spells this out further.
      +   auto-injected kanban orchestration guidance spells this out further.
       
       7. **Don't over-decompose.** A 30-second product video does NOT need 20 tasks.
          Aim for the smallest task graph that still parallelizes well and exposes the
    • website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/skills-catalog.md
      @@ -62,8 +62,7 @@ Hermes 在执行 `hermes update` 时也会同步内置技能,但同步清单
       
       | 技能 | 描述 | 路径 |
       |-------|-------------|------|
      -| [`kanban-orchestrator`](/user-guide/skills/bundled/devops/devops-kanban-orchestrator) | 面向编排器(orchestrator)配置文件的分解策略与反诱惑规则,用于通过 Kanban 路由工作。"不要自己做工作"规则和基本生命周期会自动注入每个 Kanban worker 的系统 prompt;如需更深入的细节,请加载此技能。 | `devops/kanban-orchestrator` |
      -| [`kanban-worker`](/user-guide/skills/bundled/devops/devops-kanban-worker) | Hermes Kanban worker 的陷阱、示例和边界情况。生命周期本身会作为 `KANBAN_GUIDANCE` 自动注入每个 worker 的系统 prompt(来自 `agent/prompt_builder.py`);当需要更深入细节时加载此技能。 | `devops/kanban-worker` |
      +
       
       ## dogfood
       
    • website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/features/kanban-worker-lanes.md
      @@ -7,7 +7,7 @@
       - **运维人员**:选择将哪些通道接入看板(创建哪些 profile,使用哪些 assignee)。
       - **插件/集成作者**:希望添加新的通道形态(封装 Codex / Claude Code / OpenCode 的 CLI worker、容器化审查 worker、通过 API 拉取任务的非 Hermes 服务)。
       
      -如果你编写的是 worker 代码本身——即运行在通道*内部*的 agent——请参阅 [`kanban-worker`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-worker/SKILL.md) skill,其中包含更深入的操作细节。
      +如果你编写的是 worker 代码本身——即运行在通道*内部*的 agent——kanban 生命周期与参考细节会自动注入到 worker 的系统提示中([`agent/prompt_builder.py`](https://github.com/NousResearch/hermes-agent/blob/main/agent/prompt_builder.py) 中的 `KANBAN_GUIDANCE` 块)。
       
       ## 层级结构
       
      @@ -64,7 +64,7 @@ kanban 内核强制要求每次运行恰好由其中一项终止。既未调用
       - **先将结构化元数据写入 `kanban_comment`**,因为 `kanban_block` 只携带人类可读的 `reason`。Comment 是持久的注解通道——所有与审计相关的字段(changed_files、tests_run、diff_path 或 PR url、决策记录)都应放在这里。
       - **Reviewer 批准并解除阻塞**,这将重新生成 worker 并附带 comment 线程用于后续跟进;或通过另一条 comment 要求修改,下一次 worker 运行时将通过 `kanban_show` 的上下文看到这些内容。
       
      -[`kanban-worker`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-worker/SKILL.md) skill 中有 `kanban_complete`(真正终态的任务——拼写修复、文档变更、研究报告)和 `review-required` block 模式的完整示例。
      +自动注入的 `KANBAN_GUIDANCE` 同时涵盖 `kanban_complete`(真正终态的任务——拼写修复、文档变更、研究报告)和 `review-required` block 模式。
       
       ## 日志与审计追踪
       
      @@ -80,9 +80,9 @@ kanban 内核强制要求每次运行恰好由其中一项终止。既未调用
       
       ### Hermes profile 通道(默认)
       
      -当前所有 kanban worker 采用的形态:assignee 是 profile 名称,调度器生成 `hermes -p <profile>`,worker 自动加载 [`kanban-worker`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-worker/SKILL.md) skill 以及 `KANBAN_GUIDANCE` 系统提示块,并使用 `kanban_*` 工具终止运行。除定义 profile 外无需任何额外配置。
      +当前所有 kanban worker 采用的形态:assignee 是 profile 名称,调度器生成 `hermes -p <profile>`,worker 会自动获得注入的 `KANBAN_GUIDANCE` 系统提示块,并使用 `kanban_*` 工具终止运行。除定义 profile 外无需任何额外配置。
       
      -为你的 fleet 创建 profile 时,选择与你希望 orchestrator 路由到的*角色*相匹配的名称。orchestrator(如果存在)通过 `hermes profile list` 发现你的 profile 名称——系统不假设固定的名单(orchestrator 侧的契约请参阅 [`kanban-orchestrator`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-orchestrator/SKILL.md) skill)。
      +为你的 fleet 创建 profile 时,选择与你希望 orchestrator 路由到的*角色*相匹配的名称。orchestrator(如果存在)通过 `hermes profile list` 发现你的 profile 名称——系统不假设固定的名单(orchestrator 侧的契约也是注入的 `KANBAN_GUIDANCE` 的一部分)。
       
       ### Orchestrator profile 通道
       
      @@ -110,5 +110,4 @@ profile 通道的特化形态:orchestrator 是一个 Hermes profile,其工
       
       - [Kanban 概览](./kanban) — 面向用户的介绍。
       - [Kanban 教程](./kanban-tutorial) — 开启仪表板的完整演练。
      -- [`kanban-worker`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-worker/SKILL.md) — worker 进程加载的 skill。
      -- [`kanban-orchestrator`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-orchestrator/SKILL.md) — orchestrator 侧。
      \ No newline at end of file
      +- [`KANBAN_GUIDANCE`](https://github.com/NousResearch/hermes-agent/blob/main/agent/prompt_builder.py) — 注入到每个 kanban worker 系统提示中的 worker + orchestrator 生命周期。
      \ No newline at end of file
    • website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/features/kanban.md
      @@ -240,7 +240,7 @@ kanban_create(
       kanban_complete(summary="decomposed into 2 research tasks + 1 writer; linked dependencies")
       ```
       
      -"(编排器)"工具 —— `kanban_list`、`kanban_create`、`kanban_link`、`kanban_unblock`,以及对外部任务的 `kanban_comment` —— 通过同一工具集提供;约定(由 `kanban-orchestrator` skill 强制执行)是 worker 配置文件不进行扇出或路由无关工作,编排器配置文件不执行实现工作。调度器启动的 worker 仍然针对破坏性生命周期操作限定在任务范围内,无法修改无关任务。
      +"(编排器)"工具 —— `kanban_list`、`kanban_create`、`kanban_link`、`kanban_unblock`,以及对外部任务的 `kanban_comment` —— 通过同一工具集提供;约定(编码在自动注入的 kanban 指引中)是 worker 配置文件不进行扇出或路由无关工作,编排器配置文件不执行实现工作。调度器启动的 worker 仍然针对破坏性生命周期操作限定在任务范围内,无法修改无关任务。
       
       ### 为什么使用工具而不是 shell 执行 `hermes kanban`
       
      @@ -252,7 +252,7 @@ kanban_complete(summary="decomposed into 2 research tasks + 1 writer; linked dep
       
       **对普通会话零 schema 占用。** 普通的 `hermes chat` 会话在其 schema 中没有任何 `kanban_*` 工具,除非活动配置文件为编排器工作显式启用了 `kanban` 工具集。调度器启动的任务 worker 因为设置了 `HERMES_KANBAN_TASK` 而获得任务范围的工具;编排器配置文件通过配置获得更广泛的路由界面。对于从不使用 kanban 的用户,没有工具膨胀。
       
      -`kanban-worker` 和 `kanban-orchestrator` skill 教导模型何时调用哪个工具以及调用顺序。
      +自动注入的 kanban 指引教导模型何时调用哪个工具以及调用顺序。
       
       ### 推荐的交接证据
       
      @@ -280,9 +280,9 @@ kanban_complete(summary="decomposed into 2 research tasks + 1 writer; linked dep
       
       不要将密钥、原始日志、token(令牌)、OAuth 材料和无关记录放入 `metadata`。改为存储指针和摘要。如果任务没有文件或测试,在 `summary` 中明确说明,并在 `metadata` 中放置确实存在的证据,例如来源 URL、issue id 或手动审查步骤。
       
      -### Worker skill
      +### Worker 生命周期
       
      -任何应该能够处理 kanban 任务的配置文件都必须加载 `kanban-worker` skill。它通过**工具调用**(而非 CLI 命令)教导 worker 完整的生命周期:
      +任何处理 kanban 任务的配置文件都会**自动**获得 worker 生命周期 —— 它在启动时被注入到 worker 的系统 prompt 中(`KANBAN_GUIDANCE` 块),因此**无需安装或配置任何东西**。它通过**工具调用**(而非 CLI 命令)教导 worker 完整的生命周期:
       
       1. 启动时,调用 `kanban_show()` 读取标题 + 正文 + 父级交接 + 先前尝试 + 完整评论线程。
       2. 通过终端工具执行 `cd $HERMES_KANBAN_WORKSPACE`,在那里完成工作。
      @@ -291,20 +291,6 @@ kanban_complete(summary="decomposed into 2 research tasks + 1 writer; linked dep
       
       最终的 `kanban_complete` / `kanban_block` 调用是 worker 协议的一部分。如果 worker 进程以状态 0 退出而任务仍处于 `running` 状态,调度器将其视为协议违规,发出 `protocol_violation` 事件,并在下一个 tick 自动阻塞任务而不是重新启动它进入同一循环。这通常意味着模型写了一个纯文本答案并退出,而没有使用 Kanban 工具界面。
       
      -`kanban-worker` 是一个内置 skill,在安装和更新期间同步到每个配置文件 —— 无需单独的 Skills Hub 安装步骤。验证它是否存在于你用于 kanban worker 的配置文件中(`researcher`、`writer`、`ops` 等):
      -
      -```bash
      -hermes -p <your-worker-profile> skills list | grep kanban-worker
      -```
      -
      -如果内置副本丢失,为该配置文件恢复它:
      -
      -```bash
      -hermes -p <your-worker-profile> skills reset kanban-worker --restore
      -```
      -
      -调度器在启动每个 worker 时也会自动传递 `--skills kanban-worker`,因此即使配置文件的默认 skills 配置不包含它,worker 也始终拥有该模式库。
      -
       ### 为特定任务固定额外 skill
       
       有时单个任务需要受让人配置文件默认不携带的专业上下文 —— 需要 `translation` skill 的翻译任务、需要 `github-code-review` 的审查任务、需要 `security-pr-audit` 的安全审计。与其每次都编辑受让人的配置文件,不如直接将 skill 附加到任务上。
      @@ -340,11 +326,11 @@ hermes kanban create "audit auth flow" \
       
       **从仪表盘**,在内联创建表单的 **skills** 字段中以逗号分隔输入 skill 名称。
       
      -这些 skill 是对内置 `kanban-worker` 的**补充** —— 调度器为每个 skill(以及内置的)发出一个 `--skills <name>` 标志,因此 worker 启动时加载了所有这些 skill。skill 名称必须与受让人配置文件上实际安装的 skill 匹配(运行 `hermes skills list` 查看可用内容);没有运行时安装。
      +调度器为列出的每个 skill 发出一个 `--skills <name>` 标志,因此 worker 在自动注入的 kanban 指引之上加载了所有这些 skill。skill 名称必须与受让人配置文件上实际安装的 skill 匹配(运行 `hermes skills list` 查看可用内容);没有运行时安装。
       
      -### 编排器 skill
      +### 编排器的行为方式
       
      -**行为良好的编排器不会自己做工作。** 它将用户的目标分解为任务,链接它们,将每个任务分配给你设置的配置文件之一,然后退后。`kanban-orchestrator` skill 将此编码为工具调用模式:反诱惑规则、Step-0 配置文件发现提示(调度器在未知受让人名称上静默失败,因此编排器必须将每张卡片落地到你机器上实际存在的配置文件),以及以 `kanban_create` / `kanban_link` / `kanban_comment` 为核心的分解手册。
      +**行为良好的编排器不会自己做工作。** 它将用户的目标分解为任务,链接它们,将每个任务分配给你设置的配置文件之一,然后退后。编排器指引 —— 反诱惑规则、Step-0 配置文件发现提示(调度器在未知受让人名称上静默失败,因此编排器必须将每张卡片落地到你机器上实际存在的配置文件),以及以 `kanban_create` / `kanban_link` / `kanban_comment` 为核心的分解手册 —— 会自动注入到 worker 的系统 prompt 中;无需安装任何东西。
       
       典型的编排器轮次(两个并行研究员交接给一个写作者):
       
      @@ -365,17 +351,7 @@ kanban_complete(
       )
       ```
       
      -`kanban-orchestrator` 是一个内置 skill。它在安装和更新期间同步到每个配置文件,因此无需单独的 Skills Hub 安装步骤。验证它是否存在于你的编排器配置文件中:
      -
      -```bash
      -hermes -p orchestrator skills list | grep kanban-orchestrator
      -```
      -
      -如果内置副本丢失,为该配置文件恢复它:
      -
      -```bash
      -hermes -p orchestrator skills reset kanban-orchestrator --restore
      -```
      +编排器指引随 worker 的系统 prompt 自动提供 —— 无需按配置文件安装或同步任何东西。
       
       为获得最佳效果,将其与工具集限制为看板操作(`kanban`、`gateway`、`memory`)的配置文件配对,这样编排器即使尝试也无法执行实现任务。
       
    • /dev/null
      @@ -1,207 +0,0 @@
      ----
      -title: "Kanban Orchestrator"
      -sidebar_label: "Kanban Orchestrator"
      -description: "用于通过 Kanban 路由工作的编排器 profile 的任务分解手册及反诱惑规则"
      ----
      -
      -{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
      -
      -# Kanban Orchestrator
      -
      -用于通过 Kanban 路由工作的编排器 profile 的任务分解手册及反诱惑规则。"不要自己执行工作"规则和基本生命周期会自动注入每个 kanban worker 的系统 prompt(提示词)中;本 skill 是当你专门扮演编排器角色时使用的更深层手册。
      -
      -## Skill 元数据
      -
      -| | |
      -|---|---|
      -| 来源 | 内置(默认安装) |
      -| 路径 | `skills/devops/kanban-orchestrator` |
      -| 版本 | `3.0.0` |
      -| 平台 | linux, macos, windows |
      -| 标签 | `kanban`, `multi-agent`, `orchestration`, `routing` |
      -| 相关 skill | [`kanban-worker`](/user-guide/skills/bundled/devops/devops-kanban-worker) |
      -
      -## 参考:完整 SKILL.md
      -
      -:::info
      -以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
      -:::
      -
      -# Kanban Orchestrator — 任务分解手册
      -
      -> **核心 worker 生命周期**(包括 `kanban_create` 扇出模式和"分解而非执行"规则)通过 `KANBAN_GUIDANCE` 系统 prompt 块自动注入每个 kanban 进程。本 skill 是当你作为编排器 profile、整个职责就是路由时使用的更深层手册。
      -
      -## Profile 由用户配置——不是固定名单
      -
      -Hermes 的配置因人而异。有些用户运行单个 profile 处理所有事务;有些运行小型集群(`docker-worker`、`cron-worker`);有些运行自己命名的精选专家团队。**没有默认的专家名单**——编排器 skill 不知道此机器上存在哪些 profile。
      -
      -在扇出之前,你必须基于实际存在的 profile 来制定分解方案。调度器会静默地忽略无法识别的 assignee 名称——它不会自动纠正、不会建议、也不会回退。因此,在只有 `docker-worker` 的配置上,分配给 `researcher` 的卡片会永远停留在 `ready` 状态。
      -
      -**第 0 步:在规划前发现可用的 profile。**
      -
      -使用以下方法之一:
      -
      -- `hermes profile list` — 打印此机器上已配置的 profile 表。如果有终端工具,通过终端工具运行;否则询问用户。
      -- `kanban_list(assignee="<some-name>")` — 验证单个名称。对于未知 assignee 返回空列表(而非报错),因此只能确认你已在考虑的名称。
      -- **直接询问用户。** 当目标需要多个专家时,"你配置了哪些 profile?"是一个合理的开场问题。
      -
      -将结果缓存在工作记忆中供本次对话使用。每轮都重新询问会浪费工具调用。
      -
      -## 何时使用看板(vs. 直接执行工作)
      -
      -当以下任一条件成立时,创建 Kanban 任务:
      -
      -1. **需要多个专家。** 研究 + 分析 + 写作需要三个 profile。
      -2. **工作应在崩溃或重启后继续存在。** 长期运行、周期性或重要的任务。
      -3. **用户可能需要介入。** 任意步骤需要人工参与。
      -4. **多个子任务可以并行运行。** 扇出以提高速度。
      -5. **预期需要审查/迭代。** 审查者 profile 循环处理起草者的输出。
      -6. **审计追踪很重要。** 看板行永久保存在 SQLite 中。
      -
      -如果*以上均不适用*——这是一个小型一次性推理任务——改用 `delegate_task` 或直接回答用户。
      -
      -## 反诱惑规则
      -
      -你的职责描述是"路由,不执行"。执行该规则的约束:
      -
      -- **不要自己执行工作。** 你受限的工具集通常甚至不包含用于实现的终端/文件/代码/网络工具。如果你发现自己在"快速修复这个"——停下来,为合适的专家创建任务。
      -- **对于任何具体任务,创建 Kanban 任务并分配它。** 每一次都如此。
      -- **在创建卡片之前拆分多通道请求。** 用户的一个 prompt 可能包含多个独立的工作流。先提取这些通道,然后每个通道创建一张卡片,而不是将不相关的工作打包到单个实现者卡片中。
      -- **并行运行独立通道。** 如果两张卡片不需要彼此的输出,不要链接它们,让调度器可以扇出处理。只链接真正的数据依赖。
      -- **永远不要将依赖工作创建为独立的 ready 卡片。** 如果一张卡片必须等待另一张卡片,在原始 `kanban_create` 调用中传入 `parents=[...]`。不要先创建再链接,也不要依赖卡片正文中的"等待 T1"之类的描述。
      -- **如果没有专家适合现有 profile,询问用户应创建哪个 profile 或使用哪个现有 profile。** 不要凭空发明 profile 名称;调度器会静默丢弃未知 assignee。
      -- **分解、路由、汇总——这就是全部工作。**
      -
      -## 任务分解手册
      -
      -### 第 1 步——理解目标
      -
      -如果目标不明确,提出澄清性问题。询问的成本很低;派出错误的团队代价高昂。
      -
      -### 第 2 步——草拟任务图
      -
      -在创建任何内容之前,在回复用户时大声(在响应中)草拟任务图。将每个具体工作流视为候选卡片:
      -
      -1. 从请求中提取通道。
      -2. 将每个通道映射到第 0 步中发现的某个 profile。如果某个通道不适合任何现有 profile,询问用户使用或创建哪个。
      -3. 决定每个通道是独立的还是受另一个通道门控的。
      -4. 将独立通道创建为无父链接的并行卡片。
      -5. 将综合/审查/集成卡片创建时带上其所依赖通道的父链接。使用未完成父任务创建的子任务从 `todo` 开始;调度器仅在每个父任务完成后才将其提升为 `ready`。
      -
      -应该扇出的 prompt 示例(使用占位符 profile 名称——替换为用户配置中实际存在的名称):
      -
      -- "构建一个应用" → 一张卡片给面向设计的 profile 负责产品/UI 方向,一两张卡片给工程 profile 负责实现,如果用户有审查者 profile,再加一张后续的集成/审查卡片。
      -- "修复阻塞项并检查模型变体" → 一张实现卡片用于修复阻塞项,加一张发现/研究卡片用于配置/源码验证。最终的审查者卡片可以依赖两者。
      -- "研究文档并实现" → 文档研究卡片可以与代码库发现卡片并行运行;只有当实现真正需要这些发现时才等待。
      -- "分析这张截图并找到相关代码" → 一张卡片给具备视觉能力的 profile 进行视觉分析,同时另一张卡片搜索代码库。
      -
      -"也"、"最后"或"和"等词语不自动意味着依赖关系。它们通常意味着"确保在汇报前涵盖这一点"。只有当一张卡片在另一张卡片的输出存在之前无法开始时,才链接任务。
      -
      -在创建卡片之前将任务图展示给用户。让他们纠正——包括哪个实际 profile 名称应该负责每个通道。
      -
      -### 第 3 步——创建任务并链接
      -
      -使用第 0 步中的 profile 名称。以下示例使用占位符 `<profile-A>`、`<profile-B>`、`<profile-C>`——替换为用户实际拥有的名称。
      -
      -```python
      -t1 = kanban_create(
      -    title="research: Postgres cost vs current",
      -    assignee="<profile-A>",  # whichever profile handles research on this setup
      -    body="Compare estimated infrastructure costs, migration costs, and ongoing ops costs over a 3-year window. Sources: AWS/GCP pricing, team time estimates, current Postgres bills from peers.",
      -    tenant=os.environ.get("HERMES_TENANT"),
      -)["task_id"]
      -
      -t2 = kanban_create(
      -    title="research: Postgres performance vs current",
      -    assignee="<profile-A>",  # same profile, run in parallel
      -    body="Compare query latency, throughput, and scaling characteristics at our expected data volume (~500GB, 10k QPS peak). Sources: benchmark papers, public case studies, pgbench results if easy.",
      -)["task_id"]
      -
      -t3 = kanban_create(
      -    title="synthesize migration recommendation",
      -    assignee="<profile-B>",  # whichever profile does synthesis/analysis
      -    body="Read the findings from T1 (cost) and T2 (performance). Produce a 1-page recommendation with explicit trade-offs and a go/no-go call.",
      -    parents=[t1, t2],
      -)["task_id"]
      -
      -t4 = kanban_create(
      -    title="draft decision memo",
      -    assignee="<profile-C>",  # whichever profile drafts user-facing prose
      -    body="Turn the analyst's recommendation into a 2-page memo for the CTO. Match the tone of previous decision memos in the team's knowledge base.",
      -    parents=[t3],
      -)["task_id"]
      -```
      -
      -`parents=[...]` 门控提升——子任务保持在 `todo` 状态,直到每个父任务达到 `done`,然后自动提升为 `ready`。无需手动协调;调度器和依赖引擎会处理这一切。
      -
      -如果任务图有依赖关系,先创建父卡片,捕获其返回的 id,并在子卡片的 `kanban_create` 调用中将这些 id 包含在 `parents` 列表中。避免并行创建所有卡片后再链接;这会产生一个时间窗口,调度器可能在子任务的输入存在之前就认领它。
      -
      -### 第 4 步——完成你自己的任务
      -
      -如果你是作为任务被派生的(例如,规划者 profile 被分配了 `T0: "调查 Postgres 迁移"`),用你创建内容的摘要标记它为完成:
      -
      -```python
      -kanban_complete(
      -    summary="decomposed into T1-T4: 2 research lanes in parallel, 1 synthesis on their outputs, 1 prose draft on the recommendation",
      -    metadata={
      -        "task_graph": {
      -            "T1": {"assignee": "<profile-A>", "parents": []},
      -            "T2": {"assignee": "<profile-A>", "parents": []},
      -            "T3": {"assignee": "<profile-B>", "parents": ["T1", "T2"]},
      -            "T4": {"assignee": "<profile-C>", "parents": ["T3"]},
      -        },
      -    },
      -)
      -```
      -
      -### 第 5 步——向用户汇报
      -
      -用简明的文字告诉他们你创建了什么,并说明你使用的实际 profile 名称:
      -
      -> 我已排队 4 个任务:
      -> - **T1**(`<profile-A>`):成本对比
      -> - **T2**(`<profile-A>`):性能对比,与 T1 并行
      -> - **T3**(`<profile-B>`):综合 T1 + T2 生成建议
      -> - **T4**(`<profile-C>`):将 T3 转化为 CTO 备忘录
      ->
      -> 调度器现在将认领 T1 和 T2。T3 在两者完成后启动。T4 完成时你会收到 gateway 通知。使用仪表板或 `hermes kanban tail <id>` 跟踪进度。
      -
      -## 常见模式
      -
      -**扇出 + 扇入(研究 → 综合):** N 张无父链接的研究类卡片,一张以所有研究卡片为父的综合卡片。
      -
      -**并行实现 + 验证:** 一张实现者卡片进行变更,同时一张探索/研究卡片验证配置、文档或源码映射。审查者卡片可以依赖两者。不要因为用户在一句话中同时提到了两者,就让实现者承担不相关的验证工作。
      -
      -**带门控的流水线:** `planner → implementer → reviewer`。每个阶段的 `parents=[previous_task]`。审查者阻塞或完成;如果审查者阻塞,操作员带着反馈解除阻塞并重新派发。
      -
      -**同 profile 队列:** N 个任务,全部分配给同一个 profile,彼此之间无依赖。调度器串行处理——该 profile 按优先级顺序处理它们,在自己的记忆中积累经验。
      -
      -**人工参与循环:** 任何任务都可以调用 `kanban_block()` 等待输入。调度器在 `/unblock` 后重新派发。评论线程携带完整上下文。
      -
      -## 常见陷阱
      -
      -**发明不存在的 profile 名称。** 调度器会静默地忽略无法识别的 assignee——卡片会永远停留在 `ready` 状态。始终从第 0 步发现的 profile 中分配;如果不确定,询问用户。
      -
      -**将独立通道打包到一张卡片中。** 如果用户要求两个独立的结果,创建两张卡片。示例:"修复阻塞项并检查模型变体"不是一个修复任务;为修复创建一张修复/工程卡片,为变体检查创建一张探索/研究卡片,然后可选地将审查门控在两者之上。
      -
      -**因措辞而过度链接。** "最后检查 X"如果 X 是静态配置、文档或源码发现,仍然可以与实现并行。只有当检查依赖于实现结果时,才将其链接在实现之后。
      -
      -**忘记依赖链接。** 如果任务图说 `research -> implement -> review`,不要将所有任务创建为独立的 ready 卡片。使用父链接,确保 implement/review 在其输入存在之前无法运行。
      -
      -**重新分配 vs. 新任务。** 如果审查者以"需要修改"阻塞,创建一个从审查者任务链接的**新**任务——不要用严厉的眼神重新运行同一个任务。新任务分配给原始实现者 profile。
      -
      -**链接的参数顺序。** `kanban_link(parent_id=..., child_id=...)` — 父任务在前。混淆顺序会将错误的任务降级为 `todo`。
      -
      -**如果形状取决于中间发现,不要预先创建整个任务图。** 如果 T3 的结构取决于 T1 和 T2 的发现,让 T3 作为一个"综合发现"任务存在,其第一步是读取父任务的交接内容并规划其余部分。编排器可以派生编排器。
      -
      -**Tenant 继承。** 如果你的环境中设置了 `HERMES_TENANT`,在每次 `kanban_create` 调用中传入 `tenant=os.environ.get("HERMES_TENANT")`,以确保子任务保持在同一命名空间中。
      -
      -## 恢复卡住的 worker
      -
      -当一个 worker profile 持续崩溃、产生幻觉或被自身错误阻塞时(通常是:错误的模型、缺少 skill、凭据损坏),kanban 仪表板会在任务上标记 ⚠ 徽章,并在抽屉中打开**恢复**部分。三个主要操作:
      -
      -1. **Reclaim**(或 `hermes kanban reclaim <task_id>`)——立即中止正在运行的 worker 并将任务重置为 `ready`。现有认领 TTL 约为 15 分钟;这是最快的解决路径。
      -2. **Reassign**(或 `hermes kanban reassign <task_id> <new-profile> --reclaim`)——将任务切换到不同的 profile(此配置上存在的 profile)并让调度器用新 worker 认领它。
      -3. **更改 profile 模型**——仪表板会打印 `hermes -p <profile> model` 的复制粘贴提示,因为 profile 配置存储在磁盘上;在终端中编辑它,然后 Reclaim 以使用新模型重试。
      -
      -当 worker 的 `kanban_complete(created_cards=[...])` 声明包含不存在或非该 worker profile 创建的卡片 id 时(门控会阻止完成),或者自由格式摘要引用了无法解析的 `t_<hex>` id 时(建议性文本扫描,非阻塞),会出现幻觉警告。两者都会产生审计事件,即使在恢复操作后也会持久保存——追踪记录保留用于调试。
      \ No newline at end of file
    • /dev/null
      @@ -1,202 +0,0 @@
      ----
      -title: "Kanban Worker — Hermes Kanban worker 的陷阱、示例与边界情况"
      -sidebar_label: "Kanban Worker"
      -description: "Hermes Kanban worker 的陷阱、示例与边界情况"
      ----
      -
      -{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
      -
      -# Kanban Worker
      -
      -Hermes Kanban worker 的陷阱、示例与边界情况。生命周期本身会自动注入到每个 worker 的系统 prompt(提示词)中,作为 `KANBAN_GUIDANCE`(来自 `agent/prompt_builder.py`);当你需要深入了解特定场景时,加载此 skill 即可。
      -
      -## Skill 元数据
      -
      -| | |
      -|---|---|
      -| 来源 | 内置(默认安装) |
      -| 路径 | `skills/devops/kanban-worker` |
      -| 版本 | `2.0.0` |
      -| 平台 | linux, macos, windows |
      -| 标签 | `kanban`, `multi-agent`, `collaboration`, `workflow`, `pitfalls` |
      -| 相关 skill | [`kanban-orchestrator`](/user-guide/skills/bundled/devops/devops-kanban-orchestrator) |
      -
      -## 参考:完整 SKILL.md
      -
      -:::info
      -以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
      -:::
      -
      -# Kanban Worker — 陷阱与示例
      -
      -> 你看到此 skill,是因为 Hermes Kanban 调度器以 `--skills kanban-worker` 参数将你作为 worker 派生——它会为每个被派发的 worker 自动加载。**生命周期**(6 个步骤:orient → work → heartbeat → block/complete)也存在于自动注入到你系统 prompt 中的 `KANBAN_GUIDANCE` 块里。此 skill 是更深层的细节:良好的交接形式、重试诊断、边界情况。
      -
      -## 工作区处理
      -
      -你的工作区类型决定了你在 `$HERMES_KANBAN_WORKSPACE` 内部的行为方式:
      -
      -| 类型 | 含义 | 操作方式 |
      -|---|---|---|
      -| `scratch` | 全新的临时目录,仅供你使用 | 自由读写;任务归档后会被 GC 回收。 |
      -| `dir:<path>` | 共享的持久化目录 | 其他运行实例会读取你写入的内容。将其视为长期状态。路径保证为绝对路径(内核拒绝相对路径)。 |
      -| `worktree` | 位于已解析路径的 Git worktree | 若 `.git` 不存在,先从主仓库执行 `git worktree add <path> <branch>`,然后 cd 进去正常工作。在此提交工作。 |
      -
      -## 租户隔离
      -
      -若 `$HERMES_TENANT` 已设置,则该任务属于某个租户命名空间。在读写持久化内存时,请为内存条目添加租户前缀,以防上下文跨租户泄漏:
      -
      -- 正确:`business-a: Acme is our biggest customer`
      -- 错误(会泄漏):`Acme is our biggest customer`
      -
      -## 良好的 summary + metadata 形式
      -
      -`kanban_complete(summary=..., metadata=...)` 的交接方式是下游 worker 读取你工作成果的途径。以下是有效的模式:
      -
      -**编码任务:**
      -```python
      -kanban_complete(
      -    summary="shipped rate limiter — token bucket, keys on user_id with IP fallback, 14 tests pass",
      -    metadata={
      -        "changed_files": ["rate_limiter.py", "tests/test_rate_limiter.py"],
      -        "tests_run": 14,
      -        "tests_passed": 14,
      -        "decisions": ["user_id primary, IP fallback for unauthenticated requests"],
      -    },
      -)
      -```
      -
      -**需要人工审查的编码任务(review-required):**
      -
      -对于大多数涉及代码变更的任务,在人工审查者过目之前,工作并未真正*完成*。应使用 block 而非 complete,并在 `reason` 前加 `review-required: ` 前缀,以便仪表板将该行标记为待审查。先将结构化元数据(变更文件、测试计数、diff/PR url)写入 comment,因为 `kanban_block` 只携带人类可读的原因——comment 是持久化注释的渠道。审查者可执行 `hermes kanban unblock <id>` 批准(这会携带 comment 线程重新派生你以处理后续事项),或通过另一条 comment 要求修改。
      -
      -```python
      -import json
      -
      -kanban_comment(
      -    body="review-required handoff:\n" + json.dumps({
      -        "changed_files": ["rate_limiter.py", "tests/test_rate_limiter.py"],
      -        "tests_run": 14,
      -        "tests_passed": 14,
      -        "diff_path": "/path/to/worktree",  # or PR url if pushed
      -        "decisions": ["user_id primary, IP fallback for unauthenticated requests"],
      -    }, indent=2),
      -)
      -kanban_block(
      -    reason="review-required: rate limiter shipped, 14/14 tests pass — needs eyes on the user_id/IP fallback choice before merging",
      -)
      -```
      -
      -仅在任务真正终结时使用 `kanban_complete`——例如单行拼写修复、无功能影响的文档变更,或产出物本身即为成果的研究任务。
      -
      -**研究任务:**
      -```python
      -kanban_complete(
      -    summary="3 competing libraries reviewed; vLLM wins on throughput, SGLang on latency, Tensorrt-LLM on memory efficiency",
      -    metadata={
      -        "sources_read": 12,
      -        "recommendation": "vLLM",
      -        "benchmarks": {"vllm": 1.0, "sglang": 0.87, "trtllm": 0.72},
      -    },
      -)
      -```
      -
      -**审查任务:**
      -```python
      -kanban_complete(
      -    summary="reviewed PR #123; 2 blocking issues found (SQL injection in /search, missing CSRF on /settings)",
      -    metadata={
      -        "pr_number": 123,
      -        "findings": [
      -            {"severity": "critical", "file": "api/search.py", "line": 42, "issue": "raw SQL concat"},
      -            {"severity": "high", "file": "api/settings.py", "issue": "missing CSRF middleware"},
      -        ],
      -        "approved": False,
      -    },
      -)
      -```
      -
      -请将 `metadata` 的结构设计为下游解析器(审查者、聚合器、调度器)无需重新阅读你的文字描述即可直接使用。
      -
      -## 认领你实际创建的卡片
      -
      -若你的运行产生了新的 kanban 任务(通过 `kanban_create`),请在 `kanban_complete` 的 `created_cards` 中传入这些 id。内核会验证每个 id 是否存在且由你的 profile 创建;任何幻构的 id 都会导致完成操作被阻断,并附带错误列表说明问题所在,且被拒绝的尝试会永久记录在任务的事件日志中。**只列出你从成功的 `kanban_create` 返回值中捕获的 id——绝不凭空捏造 id,绝不粘贴来自早期运行的 id,绝不认领其他 worker 创建的卡片。**
      -
      -```python
      -# 正确 — 捕获返回值,然后认领。
      -c1 = kanban_create(title="remediate SQL injection", assignee="security-worker")
      -c2 = kanban_create(title="fix CSRF middleware", assignee="web-worker")
      -
      -kanban_complete(
      -    summary="Review done; spawned remediations for both findings.",
      -    metadata={"pr_number": 123, "approved": False},
      -    created_cards=[c1["task_id"], c2["task_id"]],
      -)
      -```
      -
      -```python
      -# 错误 — 认领没有捕获返回值的 id。
      -kanban_complete(
      -    summary="Created remediation cards t_a1b2c3d4, t_deadbeef",  # 幻构
      -    created_cards=["t_a1b2c3d4", "t_deadbeef"],                   # → 门控拒绝
      -)
      -```
      -
      -若 `kanban_create` 调用失败(异常、tool_error),则卡片未被创建——不要为其包含幻构 id。重试创建,或省略该 id 并在 summary 中说明失败情况。散文扫描阶段也会捕获你自由格式 summary 中无法解析的 `t_<hex>` 引用;这些不会阻断完成操作,但会在仪表板的任务上显示为建议性警告。
      -
      -## 能快速得到回应的 block 原因
      -
      -差:`"stuck"` — 人类没有任何上下文。
      -
      -好:一句话说明你需要的具体决策。将更长的上下文作为 comment 留下。
      -
      -```python
      -kanban_comment(
      -    task_id=os.environ["HERMES_KANBAN_TASK"],
      -    body="Full context: I have user IPs from Cloudflare headers but some users are behind NATs with thousands of peers. Keying on IP alone causes false positives.",
      -)
      -kanban_block(reason="Rate limit key choice: IP (simple, NAT-unsafe) or user_id (requires auth, skips anonymous endpoints)?")
      -```
      -
      -block 消息是仪表板/gateway 通知器中显示的内容。comment 是人类打开任务时阅读的深层上下文。
      -
      -## 值得发送的 heartbeat
      -
      -好的 heartbeat 应说明进度:`"epoch 12/50, loss 0.31"`、`"scanned 1.2M/2.4M rows"`、`"uploaded 47/120 videos"`。
      -
      -差的 heartbeat:`"still working"`、空 notes、亚秒级间隔。最多每隔几分钟发送一次;对于约 2 分钟以内的任务可完全跳过。
      -
      -## 重试场景
      -
      -若你打开任务后 `kanban_show` 返回的 `runs: [...]` 中包含一个或多个已关闭的运行,说明你是一次重试。先前运行的 `outcome` / `summary` / `error` 会告诉你哪里出了问题。不要重复那条路径。典型的重试诊断:
      -
      -- `outcome: "timed_out"` — 上次尝试达到了 `max_runtime_seconds`。你可能需要将工作分块或缩短。
      -- `outcome: "crashed"` — OOM 或段错误。减少内存占用。
      -- `outcome: "spawn_failed"` + `error: "..."` — 通常是 profile 配置问题(缺少凭证、错误的 PATH)。通过 `kanban_block` 询问人类,而不是盲目重试。
      -- `outcome: "reclaimed"` + `summary: "task archived..."` — 操作员在上次运行期间将任务归档;你可能根本不应该在运行,请仔细检查状态。
      -- `outcome: "blocked"` — 上次尝试被阻断;解除阻断的 comment 现在应该已在线程中。
      -
      -## 禁止事项
      -
      -- 不要用 `delegate_task` 替代 `kanban_create`。`delegate_task` 用于你的运行内部的短期推理子任务;`kanban_create` 用于跨 agent 的、超出单次 API 循环的交接。
      -- 不要修改 `$HERMES_KANBAN_WORKSPACE` 之外的文件,除非任务正文明确要求。
      -- 不要创建分配给自己的后续任务——分配给合适的专家。
      -- 不要完成一个你实际上没有完成的任务。改为 block 它。
      -
      -## 陷阱
      -
      -**任务状态可能在调度与启动之间发生变化。** 从调度器认领任务到你的进程实际启动之间,任务可能已被 block、重新分配或归档。始终先执行 `kanban_show`。若其报告 `blocked` 或 `archived`,请停止——你不应该在运行。
      -
      -**工作区可能存在过期产物。** 尤其是 `dir:` 和 `worktree` 工作区可能包含来自先前运行的文件。阅读 comment 线程——它通常会解释你为何再次运行以及工作区处于何种状态。
      -
      -**当指导已可用时,不要依赖 CLI。** `kanban_*` 工具可在所有终端后端(Docker、Modal、SSH)上工作。从你的终端工具执行 `hermes kanban <verb>` 在容器化后端中会失败,因为 CLI 未安装在那里。如有疑问,使用工具。
      -
      -## CLI 回退(用于脚本)
      -
      -每个工具都有对应的 CLI 等价命令,供人工操作员和脚本使用:
      -- `kanban_show` ↔ `hermes kanban show <id> --json`
      -- `kanban_complete` ↔ `hermes kanban complete <id> --summary "..." --metadata '{...}'`
      -- `kanban_block` ↔ `hermes kanban block <id> "reason"`
      -- `kanban_create` ↔ `hermes kanban create "title" --assignee <profile> [--parent <id>]`
      -- 等等。
      -
      -在 agent 内部使用工具;CLI 供终端前的人类使用。
      \ No newline at end of file
    • website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/skills/optional/creative/creative-kanban-video-orchestrator.md
      @@ -21,7 +21,7 @@ description: "规划、搭建并监控由 Hermes Kanban 支撑的多智能体视
       | 许可证 | MIT |
       | 平台 | linux, macos, windows |
       | 标签 | `video`, `kanban`, `multi-agent`, `orchestration`, `production-pipeline` |
      -| 相关技能 | [`kanban-orchestrator`](/user-guide/skills/bundled/devops/devops-kanban-orchestrator)、[`kanban-worker`](/user-guide/skills/bundled/devops/devops-kanban-worker)、[`ascii-video`](/user-guide/skills/bundled/creative/creative-ascii-video)、[`manim-video`](/user-guide/skills/bundled/creative/creative-manim-video)、[`p5js`](/user-guide/skills/bundled/creative/creative-p5js)、[`comfyui`](/user-guide/skills/bundled/creative/creative-comfyui)、[`touchdesigner-mcp`](/user-guide/skills/bundled/creative/creative-touchdesigner-mcp)、[`blender-mcp`](/user-guide/skills/optional/creative/creative-blender-mcp)、[`pixel-art`](/user-guide/skills/bundled/creative/creative-pixel-art)、[`ascii-art`](/user-guide/skills/bundled/creative/creative-ascii-art)、[`songwriting-and-ai-music`](/user-guide/skills/bundled/creative/creative-songwriting-and-ai-music)、[`heartmula`](/user-guide/skills/bundled/media/media-heartmula)、[`songsee`](/user-guide/skills/bundled/media/media-songsee)、[`spotify`](/user-guide/skills/bundled/media/media-spotify)、[`youtube-content`](/user-guide/skills/bundled/media/media-youtube-content)、[`claude-design`](/user-guide/skills/bundled/creative/creative-claude-design)、[`excalidraw`](/user-guide/skills/bundled/creative/creative-excalidraw)、[`architecture-diagram`](/user-guide/skills/bundled/creative/creative-architecture-diagram)、[`concept-diagrams`](/user-guide/skills/optional/creative/creative-concept-diagrams)、[`baoyu-comic`](/user-guide/skills/bundled/creative/creative-baoyu-comic)、[`baoyu-infographic`](/user-guide/skills/bundled/creative/creative-baoyu-infographic)、[`humanizer`](/user-guide/skills/bundled/creative/creative-humanizer)、[`gif-search`](/user-guide/skills/bundled/media/media-gif-search)、[`meme-generation`](/user-guide/skills/optional/creative/creative-meme-generation) |
      +| 相关技能 | [`ascii-video`](/user-guide/skills/bundled/creative/creative-ascii-video)、[`manim-video`](/user-guide/skills/bundled/creative/creative-manim-video)、[`p5js`](/user-guide/skills/bundled/creative/creative-p5js)、[`comfyui`](/user-guide/skills/bundled/creative/creative-comfyui)、[`touchdesigner-mcp`](/user-guide/skills/bundled/creative/creative-touchdesigner-mcp)、[`blender-mcp`](/user-guide/skills/optional/creative/creative-blender-mcp)、[`pixel-art`](/user-guide/skills/bundled/creative/creative-pixel-art)、[`ascii-art`](/user-guide/skills/bundled/creative/creative-ascii-art)、[`songwriting-and-ai-music`](/user-guide/skills/bundled/creative/creative-songwriting-and-ai-music)、[`heartmula`](/user-guide/skills/bundled/media/media-heartmula)、[`songsee`](/user-guide/skills/bundled/media/media-songsee)、[`spotify`](/user-guide/skills/bundled/media/media-spotify)、[`youtube-content`](/user-guide/skills/bundled/media/media-youtube-content)、[`claude-design`](/user-guide/skills/bundled/creative/creative-claude-design)、[`excalidraw`](/user-guide/skills/bundled/creative/creative-excalidraw)、[`architecture-diagram`](/user-guide/skills/bundled/creative/creative-architecture-diagram)、[`concept-diagrams`](/user-guide/skills/optional/creative/creative-concept-diagrams)、[`baoyu-comic`](/user-guide/skills/bundled/creative/creative-baoyu-comic)、[`baoyu-infographic`](/user-guide/skills/bundled/creative/creative-baoyu-infographic)、[`humanizer`](/user-guide/skills/bundled/creative/creative-humanizer)、[`gif-search`](/user-guide/skills/bundled/media/media-gif-search)、[`meme-generation`](/user-guide/skills/optional/creative/creative-meme-generation) |
       
       ## 参考:完整 SKILL.md
       
      @@ -146,7 +146,7 @@ director profile 从此接管,通过 kanban 工具集将工作分解并路由
       
       5. **尊重现有技能。** 当某个场景适合现有技能时,相关渲染器应通过任务上的 `--skill <name>` 或 profile 中的 `always_load` 加载该技能。不要重新推导技能已提供的内容。
       
      -6. **director 绝不执行。** 即使拥有完整的 `kanban + terminal + file` 工具集,director 的 `SOUL.md` 规则也禁止其自行执行工作。它只负责分解和路由——每个具体任务都变成对专业 profile 的 `hermes kanban create` 调用。`kanban-orchestrator` 技能对此有进一步说明。
      +6. **director 绝不执行。** 即使拥有完整的 `kanban + terminal + file` 工具集,director 的 `SOUL.md` 规则也禁止其自行执行工作。它只负责分解和路由——每个具体任务都变成对专业 profile 的 `hermes kanban create` 调用。自动注入的 kanban 编排指引对此有进一步说明。
       
       7. **不要过度分解。** 一个 30 秒的产品视频**不需要** 20 个任务。目标是最小任务图,同时仍能良好并行化并暴露正确的人工审核节点。
       
    • website/sidebars.ts
      @@ -188,16 +188,6 @@ const sidebars: SidebarsConfig = {
                           'user-guide/skills/bundled/data-science/data-science-jupyter-live-kernel',
                         ],
                       },
      -                {
      -                  type: 'category',
      -                  label: 'devops',
      -                  key: 'skills-bundled-devops',
      -                  collapsed: true,
      -                  items: [
      -                    'user-guide/skills/bundled/devops/devops-kanban-orchestrator',
      -                    'user-guide/skills/bundled/devops/devops-kanban-worker',
      -                  ],
      -                },
                       {
                         type: 'category',
                         label: 'dogfood',
  • #55585 fix(kanban): unknown skill warns instead of crashing the worker

    merged to main

    files: cli.py, scripts/release.py, tui_gateway/server.py

    Show the diff
    • cli.py
      @@ -15359,7 +15359,21 @@ def main(
               )
               if missing_skills:
                   missing_display = ", ".join(missing_skills)
      -            raise ValueError(f"Unknown skill(s): {missing_display}")
      +            # If at least one skill loaded, degrade gracefully: skip the
      +            # unknown ones and continue. A typo'd skill name should not crash
      +            # the worker (which auto-blocks the Kanban task after retries).
      +            # Only when EVERY requested skill is missing do we hard-fail, so a
      +            # fully-misconfigured worker fails loudly instead of running blind.
      +            if loaded_skills:
      +                logger.warning(
      +                    "Unknown skill(s) requested, skipping: %s. "
      +                    "Continuing with: %s. "
      +                    "List available skills with `hermes skills list`.",
      +                    missing_display,
      +                    ", ".join(loaded_skills),
      +                )
      +            else:
      +                raise ValueError(f"Unknown skill(s): {missing_display}")
               if skills_prompt:
                   cli.system_prompt = "\n\n".join(
                       part for part in (cli.system_prompt, skills_prompt) if part
    • scripts/release.py
      @@ -45,6 +45,7 @@
       
       # Auto-extracted from noreply emails + manual overrides
       AUTHOR_MAP = {
      +    "[redacted:email]": "jimmyjohansson84",  # PR #27123 salvage (Kanban unknown-skill warn-instead-of-crash; #27136)
           "[redacted:email]": "theAgenticBuilder",  # PR #14180 salvage (route delegate_task progress lines through _safe_print so ACP stdio JSON-RPC frames stay clean)
           "[redacted:email]": "huangxudong663-sys",  # PR #15157 salvage (isinstance(dict) guard on tool-call model_extra; NVIDIA NIM non-dict crash)
           "[redacted:email]": "Nickperillo",  # PR #8008 salvage (Discord channel-name matching + flush pending sends on shutdown)
    • tui_gateway/server.py
      @@ -4212,12 +4212,25 @@ def _make_agent(
           if startup_skills:
               from agent.skill_commands import build_preloaded_skills_prompt
       
      -        skills_prompt, _loaded_skills, missing_skills = build_preloaded_skills_prompt(
      +        skills_prompt, loaded_skills, missing_skills = build_preloaded_skills_prompt(
                   startup_skills,
                   task_id=session_id or key,
               )
               if missing_skills:
      -            raise ValueError(f"Unknown skill(s): {', '.join(missing_skills)}")
      +            missing_display = ", ".join(missing_skills)
      +            # Degrade gracefully when some skills loaded; only hard-fail when
      +            # every requested skill is missing. Mirrors cli.py — a typo'd skill
      +            # name should not crash the worker and auto-block the Kanban task.
      +            if loaded_skills:
      +                logger.warning(
      +                    "Unknown skill(s) requested, skipping: %s. "
      +                    "Continuing with: %s. "
      +                    "List available skills with `hermes skills list`.",
      +                    missing_display,
      +                    ", ".join(loaded_skills),
      +                )
      +            else:
      +                raise ValueError(f"Unknown skill(s): {missing_display}")
               if skills_prompt:
                   system_prompt = "\n\n".join(
                       part for part in (system_prompt, skills_prompt) if part

15 PRs closed without merging

From the close comments: superseded by another PR 7 · merged via another change 5 · done elsewhere 3

  • #22933 fix(kanban): reject toolset names in task skills · merged via another change → #23273
  • #22974 fix(kanban): validate task skills and surface stuck task diagnostics · done elsewhere → 1f5983c, #23183, #22974, #23154, #23273
  • #23738 fix(packaging): ship bundled skills in wheel · merged via another change → #28421
  • #23884 fix(kanban): auto-install bundled skills (e.g. kanban-worker) on kanban init · merged via another change → 97ac94f, #28368
  • #27123 fix(gemini): add missing role field to systemInstruction for Gemma compatibility · merged via another change → 018009b, #55585, #27123
Show 10 more
  • #27201 fix(cli): unknown skills should warn instead of crash · merged via another change → 018009b
  • #29485 fix(kanban): remove missing avoid-ai-writing skill from swarm synthesizer · done elsewhere → 69b74c1, #29415
  • #34381 feat(swarm): per-swarm verifier + synthesizer body and skills overrides (#34273) · superseded by another PR → #46477
  • #41325 fix(kanban): exclude .archive/ from worker skill availability check · done elsewhere → 84e1d31, #50473
  • #41401 fix(kanban): exclude .archive/ from worker skill availability check · superseded by another PR → #41325
  • #44092 feat(kanban): validate --skill names at task creation time · superseded by another PR → #44101
  • #44101 fix(kanban): validate --skill against the worker profile's skill registry at create time · superseded by another PR → #93807
  • #45917 fix(kanban): validate per-task --skills against assignee profile at create time · superseded by another PR → #44101, #44072, #39179, #41813
  • #46477 feat(swarm): per-swarm verifier + synthesizer body and skills overrides (#34273) · superseded by another PR → #89763
  • #89763 feat(swarm): per-swarm verifier + synthesizer body and skills overrides (#34273) · superseded by another PR → #112608
Closed issues · 5
  • Closed#22921[Bug]: kanban_create accepts toolset names in skills field, causing immediate worker crash
  • Closed#23725Full kanban suite not installed with Hermes 0.130
  • Closed#27136fix(cli): unknown skills should warn instead of crash to prevent Kanban worker auto-blocking
  • Closed#29415Bug: kanban_swarm.py references missing skill avoid-ai-writing, synthesizer crashes in retry loop (v0.14.0)
  • Closed#41311[Bug]: Kanban dispatcher injects `--skills kanban-worker` for an archived skill, crashing workers (availability check rglob-matches what the loader rejects)
How this cluster was grouped
  • Link evidence (partly structural links): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text.
  • Members outside that structural core may belong to a different underlying problem.
  • Pairwise link density 0.05: 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
agent
Merged PRs
#23273, #28368, #28421, #50473, #55585
Closed issues
5
Attempts
15 PRs closed without merging
Fix link checked
30 Jun 2026

For your agent

The same facts, typed.