{"repo":"NousResearch/hermes-agent","public_id":"22921","display_label":"Kanban skill validation, availability, and packaging fixes","summary":"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.","subsystem":"agent","counts":{"members":35,"open_issues":6,"open_issues_distinct":6,"open_prs":4,"closed_issues":5,"merged_prs":5,"attempt_prs":19},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":23273},"resolution":{"state":"partially_resolved","by":"pr-23273,pr-55585"},"freshness":{"state":"verified","last_verified_at":"2026-06-30T10:42:21+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_PARTIAL","link_density":0.047596638655462174},"fix_edges":[{"issue_number":22921,"pr_number":23273,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true},{"issue_number":23725,"pr_number":28368,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false},{"issue_number":23725,"pr_number":28421,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false},{"issue_number":27136,"pr_number":55585,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true},{"issue_number":41311,"pr_number":50473,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false}],"members":[{"kind":"issue","number":22921,"title":"[Bug]: kanban_create accepts toolset names in skills field, causing immediate worker crash","url":null,"state":"closed"},{"kind":"issue","number":23725,"title":"Full kanban suite not installed with Hermes 0.130","url":null,"state":"closed"},{"kind":"issue","number":27136,"title":"fix(cli): unknown skills should warn instead of crash to prevent Kanban worker auto-blocking","url":null,"state":"closed"},{"kind":"issue","number":29415,"title":"Bug: kanban_swarm.py references missing skill avoid-ai-writing, synthesizer crashes in retry loop (v0.14.0)","url":null,"state":"closed"},{"kind":"issue","number":34273,"title":"feat(swarm): support custom verifier/synthesizer body + skills","url":null,"state":"open"},{"kind":"issue","number":35202,"title":"bug(kanban): failure_limit circuit breaker bypassed when worker crashes before first heartbeat","url":null,"state":"open"},{"kind":"issue","number":41311,"title":"[Bug]: Kanban dispatcher injects `--skills kanban-worker` for an archived skill, crashing workers (availability check rglob-matches what the loader rejects)","url":null,"state":"closed"},{"kind":"issue","number":44072,"title":"kanban create: --skill flag should validate against installed skill registry at dispatch time","url":null,"state":"open"},{"kind":"issue","number":44675,"title":"Kanban: worker crashes silently when --skill references non-existent skill in worker profile","url":null,"state":"open"},{"kind":"issue","number":54088,"title":"Kanban worker should not crash when an optional preloaded skill cannot be resolved","url":null,"state":"open"},{"kind":"issue","number":59764,"title":"Two 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","url":null,"state":"open"},{"kind":"pr","number":22933,"title":"fix(kanban): reject toolset names in task skills","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#23273","number":23273}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":22974,"title":"fix(kanban): validate task skills and surface stuck task diagnostics","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"1f5983c4c","number":0},{"kind":"pr","value":"#23183","number":23183},{"kind":"pr","value":"#22974","number":22974},{"kind":"pr","value":"#23154","number":23154},{"kind":"pr","value":"#23183","number":23183},{"kind":"pr","value":"#23183","number":23183},{"kind":"pr","value":"#23183","number":23183},{"kind":"pr","value":"#23273","number":23273},{"kind":"pr","value":"#23183","number":23183}],"category":"implemented_elsewhere","implication":"superseded"},"merged":false},{"kind":"pr","number":23273,"title":"fix(kanban): reject toolset names in task skills field (salvage #22933)","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["hermes_cli/kanban_db.py","tests/hermes_cli/test_kanban_core_functionality.py","tests/plugins/test_kanban_dashboard_plugin.py","tools/kanban_tools.py"]},{"kind":"pr","number":23738,"title":"fix(packaging): ship bundled skills in wheel","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#28421","number":28421}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":23884,"title":"fix(kanban): auto-install bundled skills (e.g. kanban-worker) on kanban init","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"97ac94fe5642e8516e917e22688142645f6250db","number":0},{"kind":"pr","value":"#28368","number":28368}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":27123,"title":"fix(gemini): add missing role field to systemInstruction for Gemma compatibility","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"018009bc3","number":0},{"kind":"pr","value":"#55585","number":55585},{"kind":"pr","value":"#27123","number":27123}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":27201,"title":"fix(cli): unknown skills should warn instead of crash","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"018009bc382de86f864e3fa8af3982c2f0aa7bfb","number":0}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":28368,"title":"fix(kanban): auto-install bundled skills (e.g. kanban-worker) on kanban init (#23884)","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["hermes_cli/kanban.py"]},{"kind":"pr","number":28421,"title":"fix(packaging): ship bundled skills in wheel (#23738)","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["hermes_constants.py","setup.py","tools/skills_sync.py"],"fix_hunks":[{"file":"hermes_constants.py","hunks":["@@ -5,6 +5,7 @@\n \"\"\"\n \n import os\n+import sysconfig\n from contextvars import ContextVar, Token\n from pathlib import Path\n ","@@ -139,6 +140,23 @@ def get_default_hermes_root() -> Path:\n     return env_path\n \n \n+def _get_packaged_data_dir(name: str) -> Path | None:\n+    \"\"\"Return an installed data-files directory if one exists.\n+\n+    Used to discover bundled skills/optional-skills when Hermes is installed\n+    from a wheel that emitted them via setuptools data_files.\n+    \"\"\"\n+    candidates = []\n+    for scheme in (\"data\", \"purelib\", \"platlib\"):\n+        raw = sysconfig.get_path(scheme)\n+        if raw:\n+            candidates.append(Path(raw) / name)\n+    for candidate in candidates:\n+        if candidate.exists():\n+            return candidate\n+    return None\n+\n+\n def get_optional_skills_dir(default: Path | None = None) -> Path:\n     \"\"\"Return the optional-skills directory, honoring package-manager wrappers.\n ","@@ -148,11 +166,34 @@ def get_optional_skills_dir(default: Path | None = None) -> Path:\n     override = os.getenv(\"HERMES_OPTIONAL_SKILLS\", \"\").strip()\n     if override:\n         return Path(override)\n+    packaged = _get_packaged_data_dir(\"optional-skills\")\n+    if packaged is not None:\n+        return packaged\n     if default is not None:\n         return default\n     return get_hermes_home() / \"optional-skills\"\n \n \n+def get_bundled_skills_dir(default: Path | None = None) -> Path:\n+    \"\"\"Return the bundled skills directory for source and packaged installs.\n+\n+    Resolution order:\n+        1. ``HERMES_BUNDLED_SKILLS`` env var (Nix wrapper / explicit override)\n+        2. Wheel-installed ``<sysconfig data>/skills`` (pip install path)\n+        3. Caller-supplied ``default`` (typically the source-checkout path)\n+        4. ``<HERMES_HOME>/skills`` last-resort\n+    \"\"\"\n+    override = os.getenv(\"HERMES_BUNDLED_SKILLS\", \"\").strip()\n+    if override:\n+        return Path(override)\n+    packaged = _get_packaged_data_dir(\"skills\")\n+    if packaged is not None:\n+        return packaged\n+    if default is not None:\n+        return default\n+    return get_hermes_home() / \"skills\"\n+\n+\n def get_hermes_dir(new_subpath: str, old_name: str) -> Path:\n     \"\"\"Resolve a Hermes subdirectory with backward compatibility.\n "]},{"file":"setup.py","hunks":["@@ -0,0 +1,28 @@\n+from __future__ import annotations\n+\n+from collections import defaultdict\n+from pathlib import Path\n+\n+from setuptools import setup\n+\n+\n+REPO_ROOT = Path(__file__).parent.resolve()\n+\n+\n+def _data_file_tree(root_name: str) -> list[tuple[str, list[str]]]:\n+    root = REPO_ROOT / root_name\n+    grouped: defaultdict[str, list[str]] = defaultdict(list)\n+    for path in sorted(root.rglob(\"*\")):\n+        if not path.is_file():\n+            continue\n+        rel_path = path.relative_to(REPO_ROOT)\n+        grouped[str(rel_path.parent)].append(str(rel_path))\n+    return sorted(grouped.items())\n+\n+\n+setup(\n+    data_files=[\n+        *_data_file_tree(\"skills\"),\n+        *_data_file_tree(\"optional-skills\"),\n+    ]\n+)"]},{"file":"tools/skills_sync.py","hunks":["@@ -26,7 +26,7 @@\n import os\n import shutil\n from pathlib import Path\n-from hermes_constants import get_hermes_home\n+from hermes_constants import get_bundled_skills_dir, get_hermes_home\n from typing import Dict, List, Tuple\n from utils import atomic_replace\n ","@@ -42,12 +42,10 @@ def _get_bundled_dir() -> Path:\n     \"\"\"Locate the bundled skills/ directory.\n \n     Checks HERMES_BUNDLED_SKILLS env var first (set by Nix wrapper),\n-    then falls back to the relative path from this source file.\n+    then a wheel-installed data dir, then falls back to the relative\n+    path from this source file.\n     \"\"\"\n-    env_override = os.getenv(\"HERMES_BUNDLED_SKILLS\")\n-    if env_override:\n-        return Path(env_override)\n-    return Path(__file__).parent.parent / \"skills\"\n+    return get_bundled_skills_dir(Path(__file__).parent.parent / \"skills\")\n \n \n def _read_manifest() -> Dict[str, str]:\n"]}]},{"kind":"pr","number":29485,"title":"fix(kanban): remove missing avoid-ai-writing skill from swarm synthesizer","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"69b74c15a324fcac460b5a143e5662036dae6387","number":0},{"kind":"pr","value":"#29415","number":29415}],"category":"implemented_elsewhere","implication":"superseded"},"merged":false,"is_fix_pr":true,"fix_tier":"suggested","fix_detail_withheld":true},{"kind":"pr","number":34381,"title":"feat(swarm): per-swarm verifier + synthesizer body and skills overrides (#34273)","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#46477","number":46477},{"kind":"pr","value":"#46477","number":46477}],"category":"superseded_by_pr","implication":"superseded"},"merged":false,"is_fix_pr":true,"fix_tier":"suggested","fix_detail_withheld":true},{"kind":"pr","number":35212,"title":"fix(kanban): count stale-claim reclaims toward circuit breaker","url":null,"state":"open","close_reason":{"category":"uncategorized","implication":"needs_llm"},"merged":false},{"kind":"pr","number":41325,"title":"fix(kanban): exclude .archive/ from worker skill availability check","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"84e1d31e5442eeff0bfcf1c2ffab6acf7fe95f45","number":0},{"kind":"pr","value":"#50473","number":50473}],"category":"implemented_elsewhere","implication":"superseded"},"merged":false},{"kind":"pr","number":41401,"title":"fix(kanban): exclude .archive/ from worker skill availability check","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#41325","number":41325},{"kind":"pr","value":"#41325","number":41325},{"kind":"pr","value":"#41325","number":41325}],"category":"superseded_by_pr","implication":"superseded"},"merged":false,"is_fix_pr":true,"fix_tier":"suggested","fix_detail_withheld":true},{"kind":"pr","number":44092,"title":"feat(kanban): validate --skill names at task creation time","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#44101","number":44101},{"kind":"pr","value":"#44101","number":44101},{"kind":"pr","value":"#44101","number":44101},{"kind":"pr","value":"#44101","number":44101}],"category":"superseded_by_pr","implication":"superseded"},"merged":false},{"kind":"pr","number":44101,"title":"fix(kanban): validate --skill against the worker profile's skill registry at create time","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#93807","number":93807}],"category":"superseded_by_pr","implication":"superseded"},"merged":false},{"kind":"pr","number":44686,"title":"fix(kanban): surface worker crash cause from log in detect_crashed_workers","url":null,"state":"open","close_reason":{"refs":[{"kind":"pr","value":"#46985","number":46985}],"category":"uncategorized","implication":"needs_llm"},"merged":false},{"kind":"pr","number":45917,"title":"fix(kanban): validate per-task --skills against assignee profile at create time","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#44101","number":44101},{"kind":"pr","value":"#44072","number":44072},{"kind":"pr","value":"#44101","number":44101},{"kind":"pr","value":"#44101","number":44101},{"kind":"pr","value":"#39179","number":39179},{"kind":"pr","value":"#41813","number":41813}],"category":"superseded_by_pr","implication":"superseded"},"merged":false},{"kind":"pr","number":46477,"title":"feat(swarm): per-swarm verifier + synthesizer body and skills overrides (#34273)","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#89763","number":89763}],"category":"superseded_by_pr","implication":"superseded"},"merged":false},{"kind":"pr","number":50473,"title":"refactor(kanban): fold worker/orchestrator skills into injected guidance","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["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","website/docs/user-guide/features/kanban.md","website/docs/user-guide/skills/bundled/autonomous-ai-agents/autonomous-ai-agents-kanban-codex-lane.md","website/docs/user-guide/skills/bundled/devops/devops-kanban-orchestrator.md","website/docs/user-guide/skills/bundled/devops/devops-kanban-worker.md","website/docs/user-guide/skills/optional/creative/creative-kanban-video-orchestrator.md","website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/skills-catalog.md","website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/features/kanban-worker-lanes.md","website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/features/kanban.md","website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/skills/bundled/devops/devops-kanban-orchestrator.md","website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/skills/bundled/devops/devops-kanban-worker.md","website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/skills/optional/creative/creative-kanban-video-orchestrator.md","website/sidebars.ts"],"fix_hunks":[{"file":"agent/prompt_builder.py","hunks":["@@ -238,6 +238,23 @@ def _strip_yaml_frontmatter(content: str) -> str:\n     \"of the decomposition. Do NOT execute the work yourself; your job is \"\n     \"routing, not implementation.\\n\"\n     \"\\n\"\n+    \"## Reference details that change outcomes\\n\"\n+    \"\\n\"\n+    \"- **Workspace.** `cd $HERMES_KANBAN_WORKSPACE` first. For a `worktree` kind \"\n+    \"with no `.git`, `git worktree add <path> \"\n+    \"${HERMES_KANBAN_BRANCH:-wt/$HERMES_KANBAN_TASK}` from the main repo, then \"\n+    \"cd there.\\n\"\n+    \"- **Deliverables.** Files a human wants go in \"\n+    \"`kanban_complete(artifacts=[<absolute paths>])` (top-level param; paths in \"\n+    \"`metadata` are NOT uploaded). Files must exist at completion.\\n\"\n+    \"- **Created cards.** List ids in `kanban_complete(created_cards=[...])` \"\n+    \"ONLY when captured from a successful `kanban_create` return — never invent \"\n+    \"or paste ids; the kernel rejects the completion on any phantom id.\\n\"\n+    \"- **Orchestrating: discover profiles first.** The dispatcher SILENTLY \"\n+    \"drops a card with an unknown assignee (it sits in `ready` forever). Ground \"\n+    \"every assignee in a real profile (`hermes profile list`, or ask the user), \"\n+    \"and express dependencies via `parents=[...]` on `kanban_create`, not prose.\\n\"\n+    \"\\n\"\n     \"## Do NOT\\n\"\n     \"\\n\"\n     \"- Do not shell out to `hermes kanban <verb>` for board operations. Use \""]},{"file":"agent/skill_utils.py","hunks":["@@ -280,9 +280,9 @@ def skill_matches_environment(frontmatter: Dict[str, Any]) -> bool:\n     This is an OFFER-time filter: it controls whether a skill shows up in the\n     skills index / autocomplete / slash-command list. It is intentionally NOT\n     enforced by ``skill_view`` or ``--skills`` preloading — an explicit load is\n-    explicit consent, and load-bearing force-loads (e.g. the kanban dispatcher\n-    injecting ``--skills kanban-worker``) must always succeed regardless of how\n-    the offer surfaces filter the skill.\n+    explicit consent, and load-bearing force-loads (e.g. a dispatcher pinning\n+    a task to a specialist skill via ``--skills``) must always succeed\n+    regardless of how the offer surfaces filter the skill.\n \n     A skill matches when ANY of its declared environments is currently active\n     (OR semantics, mirroring ``platforms``). Unknown env tags fail open."]},{"file":"hermes_cli/kanban.py","hunks":["@@ -26,7 +26,7 @@\n \n from hermes_cli import kanban_db as kb\n from hermes_cli import kanban_swarm as ks\n-from hermes_cli.profiles import get_active_profile_name, get_profile_dir, seed_profile_skills\n+from hermes_cli.profiles import get_active_profile_name\n \n \n # ---------------------------------------------------------------------------","@@ -330,8 +330,8 @@ def build_parser(parent_subparsers: argparse._SubParsersAction) -> argparse.Argu\n                           help=\"Author name recorded on the task (default: user)\")\n     p_create.add_argument(\"--skill\", action=\"append\", default=[], dest=\"skills\",\n                           help=\"Skill to force-load into the worker \"\n-                               \"(repeatable). Appended to the built-in \"\n-                               \"kanban-worker skill. Example: \"\n+                               \"(repeatable). The kanban lifecycle is already \"\n+                               \"injected automatically. Example: \"\n                                \"--skill translation --skill github-code-review\")\n     p_create.add_argument(\"--max-retries\", type=int, default=None,\n                           metavar=\"N\",","@@ -1223,21 +1223,6 @@ def _cmd_init(args: argparse.Namespace) -> int:\n     path = kb.init_db()\n     print(f\"Kanban DB initialized at {path}\")\n \n-    # Seed bundled skills (e.g. kanban-worker) into the active profile so\n-    # the kanban dispatcher can use them without a separate `hermes profile\n-    # create` step.  This is best-effort — a missing or broken profile is\n-    # not fatal to `kanban init`.\n-    try:\n-        profile_name = get_active_profile_name() or \"default\"\n-        profile_dir = get_profile_dir(profile_name)\n-        result = seed_profile_skills(profile_dir, quiet=True)\n-        if result:\n-            copied = result.get(\"copied\", [])\n-            if copied:\n-                print(f\"Seeded skill(s) into profile {profile_name}: {', '.join(copied)}\")\n-    except Exception:\n-        pass  # best-effort\n-\n     print()\n     # Enumerate profiles on disk so the user knows what assignees are\n     # already addressable. Multica does this auto-detection on its","@@ -1461,8 +1446,7 @@ def _cmd_show(args: argparse.Namespace) -> int:\n         parents = kb.parent_ids(conn, args.task_id)\n         children = kb.child_ids(conn, args.task_id)\n         runs = kb.list_runs(conn, args.task_id, **rsk)\n-        # Workers hand off via ``task_runs.summary`` (kanban-worker skill);\n-        # ``tasks.result`` is left NULL unless the caller explicitly passed\n+        # Workers hand off via ``task_runs.summary``; ``tasks.result`` is left NULL unless the caller explicitly passed\n         # ``result=``. Surfacing the latest summary here keeps ``show`` from\n         # looking like a no-op when the worker actually did real work.\n         latest_summary = kb.latest_summary(conn, args.task_id)"]},{"file":"hermes_cli/kanban_db.py","hunks":["@@ -804,10 +804,9 @@ class Task:\n     current_run_id: Optional[int] = None\n     workflow_template_id: Optional[str] = None\n     current_step_key: Optional[str] = None\n-    # Force-loaded skills for the worker on this task (appended to the\n-    # dispatcher's built-in `kanban-worker` via --skills). Stored as a\n-    # JSON array of skill names. None = use only the defaults; empty\n-    # list = explicitly no extra skills.\n+    # Force-loaded skills for the worker on this task (passed via\n+    # --skills). Stored as a JSON array of skill names. None = use only\n+    # the defaults; empty list = explicitly no extra skills.\n     skills: Optional[list] = None\n     model_override: Optional[str] = None\n     # Per-task override for the consecutive-failure circuit breaker.","@@ -1045,8 +1044,7 @@ class Event:\n     workflow_template_id TEXT,\n     current_step_key     TEXT,\n     -- Force-loaded skills for the worker on this task, stored as JSON.\n-    -- Appended to the dispatcher's built-in `--skills kanban-worker`.\n-    -- NULL or empty array = no extras.\n+    -- Passed to the worker via `--skills`. NULL or empty array = no extras.\n     skills               TEXT,\n     -- Per-task model override. When set, the dispatcher passes -m <model>\n     -- to the worker, overriding the profile's default model. NULL = use","@@ -1848,8 +1846,7 @@ def _migrate_add_optional_columns(conn: sqlite3.Connection) -> None:\n         )\n     if \"skills\" not in cols:\n         # JSON array of skill names the dispatcher force-loads into the\n-        # worker (additive to the built-in `kanban-worker`). NULL is fine\n-        # for existing rows.\n+        # worker via --skills. NULL is fine for existing rows.\n         _add_column_if_missing(conn, \"tasks\", \"skills\", \"skills TEXT\")\n \n     if \"max_retries\" not in cols:","@@ -2285,9 +2282,8 @@ def create_task(\n \n     ``skills`` is an optional list of skill names to force-load into\n     the worker when dispatched. Stored as JSON; the dispatcher passes\n-    each name to ``hermes --skills ...`` alongside the built-in\n-    ``kanban-worker``. Use this to pin a task to a specialist skill\n-    (e.g. ``skills=[\"translation\"]`` so the worker loads the\n+    each name to ``hermes --skills ...``. Use this to pin a task to a\n+    specialist skill (e.g. ``skills=[\"translation\"]`` so the worker loads the\n     translation skill regardless of the profile's default config).\n     \"\"\"\n     assignee = _canonical_assignee(assignee)","@@ -2348,7 +2344,7 @@ def create_task(\n                 f\"{quoted} {noun}, not skill name(s). \"\n                 \"Put toolsets in the assignee profile's `toolsets:` config \"\n                 \"instead of per-task skills. Skills are named skill bundles \"\n-                \"(e.g. `kanban-worker`, `blogwatcher`); toolsets are runtime \"\n+                \"(e.g. `blogwatcher`, `github-code-review`); toolsets are runtime \"\n                 \"capabilities (e.g. `web`, `browser`, `terminal`).\"\n             )\n         skills_list = cleaned","@@ -6994,11 +6990,11 @@ def _dispatch_once_locked(\n         if claimed.workspace_kind == \"worktree\":\n             set_branch_name(conn, claimed.id, resolved_branch_name or (claimed.branch_name or \"\").strip() or f\"wt/{claimed.id}\")\n         _maybe_emit_scratch_tip(conn, claimed.id, claimed.workspace_kind)\n-        # Force-load sdlc-review skill for review agents.  The\n-        # _default_spawn function already auto-loads kanban-worker, and\n-        # appends task.skills via --skills.  Setting task.skills here\n-        # means the review agent gets both kanban-worker (lifecycle)\n-        # and sdlc-review (review logic: AC verification, merge, etc.).\n+        # Force-load the sdlc-review skill for review agents — it carries\n+        # the review logic (AC verification, merge, etc.). The mandatory\n+        # kanban lifecycle is already injected into every worker's system\n+        # prompt via KANBAN_GUIDANCE, so this is the only extra skill the\n+        # review agent needs.\n         claimed.skills = [\"sdlc-review\"]\n         _spawn = spawn_fn if spawn_fn is not None else _default_spawn\n         try:","@@ -7223,41 +7219,6 @@ def _resolve_hermes_argv() -> list[str]:\n     return _module_hermes_argv()\n \n \n-def _kanban_worker_skill_available(hermes_home: Optional[str]) -> bool:\n-    \"\"\"True if the bundled ``kanban-worker`` skill resolves for the home the\n-    spawned worker will run under.\n-\n-    The dispatcher injects ``--skills kanban-worker`` into every worker. When\n-    the worker activates a profile (``hermes -p <name>``), its ``SKILLS_DIR``\n-    becomes ``<profile_home>/skills`` — which on many profiles does NOT contain\n-    the bundled skill (it ships in the *default* root home, not every\n-    profile-scoped skills dir). Preloading a missing skill is fatal at CLI\n-    startup (``ValueError: Unknown skill(s): kanban-worker``), aborting the\n-    worker before the agent loop runs. Gate the flag on actual resolvability;\n-    the kanban lifecycle contract is still injected via ``KANBAN_GUIDANCE``, so\n-    omitting the flag only drops the supplementary pattern library.\n-    \"\"\"\n-    from pathlib import Path as _Path\n-\n-    # An unset HERMES_HOME means the worker falls back to the default root\n-    # home (``~/.hermes``), which ships the bundled skill.\n-    base = _Path(hermes_home) if hermes_home else (_Path.home() / \".hermes\")\n-    skills_root = base / \"skills\"\n-    if not skills_root.is_dir():\n-        return False\n-    # Canonical bundled location first (cheap), then a bounded scan for\n-    # profiles that have it nested elsewhere.\n-    if (skills_root / \"devops\" / \"kanban-worker\" / \"SKILL.md\").is_file():\n-        return True\n-    try:\n-        for skill_md in skills_root.rglob(\"kanban-worker/SKILL.md\"):\n-            if skill_md.is_file():\n-                return True\n-    except OSError:\n-        pass\n-    return False\n-\n-\n def _worker_terminal_timeout_env(\n     max_runtime_seconds: Optional[int],\n     current_timeout: Optional[str],","@@ -7440,32 +7401,14 @@ def _default_spawn(\n         # profile-local worker sessions still register configured hooks.\n         \"--accept-hooks\",\n     ]\n-    # Auto-load the kanban-worker skill so every dispatched worker\n-    # has the pattern library (good summary/metadata shapes, retry\n-    # diagnostics, block-reason examples) in its context, even if\n-    # the profile hasn't wired it into skills config. The MANDATORY\n-    # lifecycle is already in the system prompt via KANBAN_GUIDANCE;\n-    # this skill is the deeper reference. Users can point a profile\n-    # at a different/additional skill via config if they want —\n-    # --skills is additive to the profile's default skill set.\n-    #\n-    # Only add the flag when the skill actually resolves for the home\n-    # the worker runs under: the bundled skill is absent from many\n-    # profile-scoped skills dirs, and preloading a missing skill is\n-    # fatal at CLI startup. Omitting it is safe — the lifecycle\n-    # contract still ships via KANBAN_GUIDANCE.\n-    if _kanban_worker_skill_available(env.get(\"HERMES_HOME\")):\n-        cmd.extend([\"--skills\", \"kanban-worker\"])\n     # Per-task force-loaded skills. Each name goes in its own\n     # `--skills X` pair rather than a single comma-joined arg: the CLI\n     # accepts both forms (action='append' + comma-split), but\n     # per-name pairs are easier to read in `ps` output and avoid any\n     # quoting ambiguity if a skill name ever contains unusual chars.\n-    # Dedupe against the built-in so we don't double-load kanban-worker\n-    # if a task author asks for it explicitly.\n     if task.skills:\n         for sk in task.skills:\n-            if sk and sk != \"kanban-worker\":\n+            if sk:\n                 cmd.extend([\"--skills\", sk])\n     if task.model_override:\n         cmd.extend([\"-m\", task.model_override])","@@ -8322,7 +8265,7 @@ def latest_run(conn: sqlite3.Connection, task_id: str) -> Optional[Run]:\n def latest_summary(conn: sqlite3.Connection, task_id: str) -> Optional[str]:\n     \"\"\"Return the latest non-null ``task_runs.summary`` for ``task_id``.\n \n-    The kanban-worker skill writes its handoff to ``task_runs.summary``\n+    The worker writes its handoff to ``task_runs.summary``\n     via ``complete_task(summary=...)``; ``tasks.result`` is left empty\n     unless the caller passes ``result=`` explicitly. Dashboards and CLI\n     \"show\" views need this value to surface what a worker actually did"]},{"file":"hermes_cli/kanban_swarm.py","hunks":["@@ -124,7 +124,6 @@ def create_swarm(\n         idempotency_key=idempotency_key,\n         workspace_kind=workspace_kind,\n         workspace_path=workspace_path,\n-        skills=[\"kanban-orchestrator\"],\n     )\n \n     # If idempotency returned an existing non-archived root, do not duplicate the"]},{"file":"optional-skills/creative/kanban-video-orchestrator/SKILL.md","hunks":["@@ -8,7 +8,7 @@ platforms: [linux, macos, windows]\n metadata:\n   hermes:\n     tags: [video, kanban, multi-agent, orchestration, production-pipeline]\n-    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]\n+    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]\n     credits: |\n       The single-project workspace layout, profile-config patching pattern,\n       SOUL.md-per-profile model, TEAM.md task-graph convention, and","@@ -174,8 +174,9 @@ task graphs. See **[references/examples.md](references/examples.md)**.\n 6. **The director never executes.** Even with the full `kanban + terminal +\n    file` toolset, the director's `SOUL.md` rules forbid it from executing\n    work itself. It decomposes and routes only — every concrete task becomes\n-   a `hermes kanban create` call to a specialist profile. The\n-   `kanban-orchestrator` skill spells this out further.\n+   a `hermes kanban create` call to a specialist profile. The kanban\n+   orchestration guidance auto-injected into every kanban worker's system\n+   prompt spells this out further.\n \n 7. **Don't over-decompose.** A 30-second product video does NOT need 20 tasks.\n    Aim for the smallest task graph that still parallelizes well and exposes the"]},{"file":"optional-skills/creative/kanban-video-orchestrator/assets/setup.sh.tmpl","hunks":["@@ -64,7 +64,7 @@ echo \"═══ Configuring profiles ═══\"\n configure_profile() {\n     local profile=\"$1\"\n     local toolsets_json=\"$2\"     # JSON array string, e.g. '[\"kanban\",\"terminal\",\"file\"]'\n-    local skills_json=\"$3\"       # JSON array string, e.g. '[\"kanban-worker\",\"ascii-video\"]'\n+    local skills_json=\"$3\"       # JSON array string, e.g. '[\"ascii-video\"]'\n     python3 - \"$profile\" \"$toolsets_json\" \"$skills_json\" \"$WORKSPACE\" <<'PY'\n \"\"\"Patch a Hermes profile config.yaml using PyYAML so we don't depend on the\n exact default-config string format. Validates the patch took effect and exits"]},{"file":"optional-skills/creative/kanban-video-orchestrator/references/examples.md","hunks":["@@ -39,8 +39,8 @@ T8  reviewer         final QA                                 (parent: T7)\n **Key choices:**\n - Local ComfyUI via `comfyui` skill is preferred over external API for\n   cost/control — but external APIs are fine if ComfyUI isn't installed\n-- `editor` profile is ffmpeg-only, no Hermes skill required beyond\n-  `kanban-worker`\n+- `editor` profile is ffmpeg-only, no Hermes skill required (kanban guidance\n+  is auto-injected into every kanban worker)\n - Storyboarder produces `storyboard.excalidraw` alongside the markdown\n \n ## Example 2 — Product / marketing teaser"]},{"file":"optional-skills/creative/kanban-video-orchestrator/references/kanban-setup.md","hunks":["@@ -101,7 +101,7 @@ default-config schema drift:\n configure_profile() {\n     local profile=\"$1\"\n     local toolsets_json=\"$2\"     # JSON array, e.g. '[\"kanban\",\"terminal\",\"file\"]'\n-    local skills_json=\"$3\"       # JSON array, e.g. '[\"kanban-worker\",\"ascii-video\"]'\n+    local skills_json=\"$3\"       # JSON array, e.g. '[\"ascii-video\"]'\n     python3 - \"$profile\" \"$toolsets_json\" \"$skills_json\" <<'PY'\n import json, os, sys, yaml\n profile, ts_json, sk_json = sys.argv[1:4]","@@ -133,16 +133,16 @@ the entire production. **Critical content for the director's SOUL.md:**\n \n - **Anti-temptation rules:** \"Do not execute the work yourself. For every\n   concrete task, create a kanban task and assign it. Decompose, route, comment,\n-  approve — that's the whole job.\" (The `kanban-orchestrator` skill provides\n-  the deeper playbook; load it.)\n+  approve — that's the whole job.\" (The kanban orchestration guidance is\n+  auto-injected into every kanban worker's system prompt — no skill to load.)\n - **Decomposition steps:** Read `brief.md`, `TEAM.md`, `taste/`. Use the team\n   graph in `TEAM.md` to fan out tasks.\n - **The workspace_path rule** (see below).\n \n Other profiles' SOUL.md is briefer; mostly mechanical: who you are, what you\n read, what you produce, what skills/tools to use, where to write outputs.\n-Most non-director profiles should `always_load: kanban-worker` for the\n-deeper-than-baseline kanban guidance.\n+The kanban lifecycle guidance is auto-injected into every kanban worker's\n+system prompt, so no profile needs to load a kanban skill.\n \n ### Initial kanban task\n "]},{"file":"optional-skills/creative/kanban-video-orchestrator/references/role-archetypes.md","hunks":["@@ -18,15 +18,16 @@ The vision-holder. Reads the brief and brand guide, decomposes into a task\n graph, comments to steer creative direction, approves the final cut.\n \n - **Toolsets:** kanban, terminal, file\n-- **Skills:** `kanban-orchestrator`. The kanban plugin auto-injects baseline\n-  orchestration guidance for free; `kanban-orchestrator` is the deeper\n-  decomposition playbook. Add `creative-ideation` if the brief is wide-open\n-  and needs framing help.\n+- **Skills:** no extra skill needed — the kanban orchestration guidance\n+  (decomposition playbook, \"decompose, don't execute\" discipline) is\n+  auto-injected into every kanban worker's system prompt. Add\n+  `creative-ideation` if the brief is wide-open and needs framing help.\n - **Personality:** Tied to the brand voice — see `assets/soul.md.tmpl`\n \n The director has the same toolset as everyone else, but its `SOUL.md` rules\n **forbid** execution. The \"decompose, don't execute\" discipline is enforced\n-by personality + the kanban-orchestrator skill, not by missing tools.\n+by personality + the auto-injected kanban orchestration guidance, not by\n+missing tools.\n \n ## Pre-production roles\n ","@@ -38,7 +39,7 @@ Writes scripts, dialogue, voiceover copy, narration. Use for any video with\n spoken or written words beyond a tagline.\n \n - **Toolsets:** kanban, file\n-- **Skills:** `kanban-worker`, `humanizer` (post-process to strip AI-tells)\n+- **Skills:** `humanizer` (post-process to strip AI-tells)\n - **Outputs:** `script.md`, `narration.md`, `dialogue/scene-NN.md`\n \n ### copywriter","@@ -47,7 +48,7 @@ Like `writer` but specifically for marketing copy: taglines, CTAs, voiceover\n scripts for product videos.\n \n - **Toolsets:** kanban, file\n-- **Skills:** `kanban-worker`, `humanizer`\n+- **Skills:** `humanizer`\n - **Outputs:** `copy.md`\n \n ### concept-artist / visual-designer","@@ -58,7 +59,7 @@ follow. Often produces still reference frames using image-generation APIs or\n local skills.\n \n - **Toolsets:** kanban, terminal, file\n-- **Skills:** `kanban-worker` plus any project-specific design skill —\n+- **Skills:** any project-specific design skill —\n   `claude-design` (UI/web), `sketch` (quick mockup variants),\n   `popular-web-designs` (matching known web aesthetic), `pixel-art` (retro),\n   `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\n film and music video. Often pairs with a diagramming tool.\n \n - **Toolsets:** kanban, file\n-- **Skills:** `kanban-worker` plus a diagram skill — `excalidraw` (sketch),\n+- **Skills:** a diagram skill — `excalidraw` (sketch),\n   `architecture-diagram` (technical/system), `concept-diagrams` (educational/\n   scientific)\n - **Outputs:** `storyboard.md` with one row per scene/shot, optional","@@ -83,7 +84,7 @@ Designs the visual language: framing, color, motion, transitions. Reviews\n generator output for visual consistency. Hands off per-scene `VISUAL_SPEC.md`.\n \n - **Toolsets:** kanban, terminal, file, video, vision\n-- **Skills:** `kanban-worker` plus the visual skill that matches the project\n+- **Skills:** the visual skill that matches the project\n   (e.g., `ascii-video` for ASCII work, `manim-video` for explainers,\n   `touchdesigner-mcp` for real-time visuals, etc.)\n - **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.\n | `renderer-video` | (external image-to-video API: Runway / Kling / Luma) | Animating still images in narrative film |\n | `renderer-motion-graphics` | (external — Remotion CLI) | Motion graphics, kinetic typography, UI animations |\n \n-For external-API renderers, the profile holds the API client logic; only\n-`kanban-worker` is loaded, plus the terminal toolset and the API key.\n+For external-API renderers, the profile holds the API client logic; no extra\n+skill is loaded (kanban guidance is auto-injected into every kanban worker),\n+plus the terminal toolset and the API key.\n \n ### image-generator\n ","@@ -133,7 +135,7 @@ Specifically for text-to-image generation. Often produces stills that go to\n `renderer-video` for animation.\n \n - **Toolsets:** kanban, terminal, file\n-- **Skills:** `kanban-worker`, optionally `comfyui` (drives a local\n+- **Skills:** optionally `comfyui` (drives a local\n   ComfyUI install for image generation)\n - **External APIs (alternative to local ComfyUI):** FAL, Replicate, OpenAI\n   Images, Midjourney","@@ -146,7 +148,7 @@ ComfyUI's image-to-video workflows locally. Almost always follows\n `image-generator` in narrative film pipelines.\n \n - **Toolsets:** kanban, terminal, file\n-- **Skills:** `kanban-worker`, optionally `comfyui` (for local image-to-video\n+- **Skills:** optionally `comfyui` (for local image-to-video\n   workflows like AnimateDiff or WAN)\n - **External APIs:** Runway, Kling, Luma, Pika\n - **Outputs:** `scenes/scene-NN/clip.mp4`","@@ -159,7 +161,7 @@ spectrograms when the editor or renderer needs a visual reference of the\n audio's energy.\n \n - **Toolsets:** kanban, terminal, file\n-- **Skills:** `kanban-worker`, `songsee` (audio visualization), plus one of:\n+- **Skills:** `songsee` (audio visualization), plus one of:\n   - `songwriting-and-ai-music` — when commissioning lyrics + Suno prompts\n   - `heartmula` — when generating music with the open-source local model\n   - `spotify` — when sourcing existing tracks","@@ -169,11 +171,11 @@ audio's energy.\n ### voice-talent / narrator\n \n Generates voiceover audio. Calls a TTS API directly; no Hermes skill required\n-beyond `kanban-worker`. The user can also supply pre-recorded VO instead of\n-generation.\n+(kanban guidance is auto-injected into every kanban worker). The user can also\n+supply pre-recorded VO instead of generation.\n \n - **Toolsets:** kanban, terminal, file\n-- **Skills:** `kanban-worker`\n+- **Skills:** none — kanban guidance is auto-injected into every kanban worker\n - **External APIs:** ElevenLabs, OpenAI TTS, etc.\n - **Outputs:** `audio/voiceover/line-NN.mp3`, `audio/voiceover/timeline.mp3`\n ","@@ -183,7 +185,7 @@ Sound effects and ambient design. Often optional unless the brief calls for\n sound design specifically.\n \n - **Toolsets:** kanban, terminal, file\n-- **Skills:** `kanban-worker`, `songsee` for audio-feature visualization when\n+- **Skills:** `songsee` for audio-feature visualization when\n   designing to a track\n - **Outputs:** `audio/sfx/*.mp3`\n ","@@ -195,7 +197,7 @@ Assembles the final cut from clips. Uses ffmpeg for stitching, fades,\n transitions. Reviews each clip for pacing and quality before assembly.\n \n - **Toolsets:** kanban, terminal, file\n-- **Skills:** `kanban-worker`\n+- **Skills:** none — kanban guidance is auto-injected into every kanban worker\n - **External tools:** ffmpeg, ffprobe\n - **Outputs:** `output/final.mp4`, `output/final-noaudio.mp4`\n ","@@ -206,7 +208,7 @@ brand-consistent output and the editor just stitches, the colorist is overkill.\n Worth including for narrative film with hero shots.\n \n - **Toolsets:** kanban, terminal, file\n-- **Skills:** `kanban-worker`\n+- **Skills:** none — kanban guidance is auto-injected into every kanban worker\n - **Outputs:** `output/final-graded.mp4`\n \n ### audio-mixer","@@ -215,7 +217,7 @@ Mixes voiceover + music + SFX into a final audio track. Sets levels, ducks\n music under VO, normalizes loudness (LUFS).\n \n - **Toolsets:** kanban, terminal, file\n-- **Skills:** `kanban-worker`\n+- **Skills:** none — kanban guidance is auto-injected into every kanban worker\n - **External tools:** ffmpeg with `loudnorm` filter, optional `sox`\n - **Outputs:** `audio/final-mix.mp3`\n ","@@ -225,7 +227,7 @@ Burns subtitles into the video, generates SRT, handles accessibility. Can also\n generate captions from audio via Whisper.\n \n - **Toolsets:** kanban, terminal, file\n-- **Skills:** `kanban-worker`\n+- **Skills:** none — kanban guidance is auto-injected into every kanban worker\n - **External tools:** Whisper (CLI or API), ffmpeg subtitle filters\n - **Outputs:** `output/captions.srt`, `output/final-captioned.mp4`\n ","@@ -235,7 +237,7 @@ Final encode + format variants. Produces deliverables for each platform target\n (square for IG, vertical for TikTok, full HD for YouTube, etc.).\n \n - **Toolsets:** kanban, terminal, file\n-- **Skills:** `kanban-worker`\n+- **Skills:** none — kanban guidance is auto-injected into every kanban worker\n - **Outputs:** `output/final-1080.mp4`, `output/final-9x16.mp4`, etc.\n \n ## QA roles","@@ -248,7 +250,7 @@ quality). Distinct from the cinematographer (who reviews visuals during\n production) and the editor (who reviews for assembly).\n \n - **Toolsets:** kanban, terminal, file, video, vision\n-- **Skills:** `kanban-worker`\n+- **Skills:** none — kanban guidance is auto-injected into every kanban worker\n - **Review tools:** `video_analyze` (native clip review via multimodal LLM),\n   `vision_analyze` (frame/thumbnail review), ffprobe\n - **Outputs:** `review-notes.md`, comments on tasks","@@ -260,7 +262,7 @@ when the brand guidelines are detailed and a generic reviewer might miss\n violations.\n \n - **Toolsets:** kanban, file\n-- **Skills:** `kanban-worker`\n+- **Skills:** none — kanban guidance is auto-injected into every kanban worker\n - **Outputs:** comments + `brand-review.md`\n \n ## Composing teams — heuristics"]},{"file":"optional-skills/creative/kanban-video-orchestrator/references/tool-matrix.md","hunks":["@@ -50,18 +50,12 @@ called from the terminal toolset; they don't appear in `always_load`.\n | `gif-search` | Find existing GIFs | Editor / concept artist sourcing references |\n | `gifs` | GIF tooling | Masterer producing GIF deliverables |\n \n-### Kanban infrastructure (`hermes-agent/skills/devops/`)\n-\n-| Skill | What it does | When to load |\n-|-------|--------------|--------------|\n-| `kanban-orchestrator` | Decomposition playbook + anti-temptation rules for orchestrator profiles | Director only |\n-| `kanban-worker` | Pitfalls, examples, edge cases for kanban workers (deeper than auto-injected guidance) | Any profile — load when handling tricky multi-step workflows |\n+### Kanban infrastructure\n \n The kanban plugin auto-injects baseline orchestration guidance into every\n worker's system prompt — the `kanban_create` fan-out pattern, claim/handoff\n-lifecycle, and the \"decompose, don't execute\" rule for orchestrators.\n-`kanban-orchestrator` and `kanban-worker` are deeper playbooks loaded when a\n-profile needs them.\n+lifecycle, and the \"decompose, don't execute\" rule for orchestrators. There is\n+no kanban skill to load; the guidance is always present for kanban workers.\n \n ## External tools (called from terminal toolset)\n ","@@ -102,8 +96,7 @@ toolsets:\n   - terminal\n   - file\n skills:\n-  always_load:\n-    - kanban-orchestrator\n+  always_load: []\n ```\n \n The director's terminal access is conventional but the SOUL.md rules forbid","@@ -117,7 +110,6 @@ toolsets:\n   - file\n skills:\n   always_load:\n-    - kanban-worker\n     - humanizer            # post-process scripts to strip AI-tells\n ```\n ","@@ -132,7 +124,6 @@ toolsets:\n   - file\n skills:\n   always_load:\n-    - kanban-worker\n     # plus one or more (style-dependent):\n     # - claude-design       (UI / web product video)\n     # - sketch              (quick mockup variants)","@@ -151,7 +142,6 @@ toolsets:\n   - file\n skills:\n   always_load:\n-    - kanban-worker\n     # one of:\n     # - excalidraw              (sketch storyboards)\n     # - architecture-diagram    (technical/system content)","@@ -169,7 +159,6 @@ toolsets:\n   - vision              # vision_analyze — review stills / exported frames\n skills:\n   always_load:\n-    - kanban-worker\n     # the visual skill that matches the project, e.g.:\n     # - ascii-video            (ASCII projects)\n     # - manim-video            (math/explainer)","@@ -188,7 +177,6 @@ toolsets:\n   - file\n skills:\n   always_load:\n-    - kanban-worker\n     # ONE skill per renderer variant (or empty for external-API renderers):\n     # - ascii-video               (renderer-ascii)\n     # - manim-video               (renderer-manim)","@@ -202,9 +190,9 @@ skills:\n ```\n \n For external-API renderers (image-to-video-generator using Runway, voice-talent\n-using ElevenLabs, renderer-motion-graphics using Remotion), `always_load` only\n-contains `kanban-worker` — the role's work is API-driven and the API key +\n-terminal commands suffice.\n+using ElevenLabs, renderer-motion-graphics using Remotion), `always_load` is\n+empty — the role's work is API-driven and the API key +\n+terminal commands suffice (kanban guidance is auto-injected regardless).\n \n For multi-skill renderer setups (rare — usually one variant per skill is\n cleaner) use `--skill <name>` on individual `kanban_create` calls to override","@@ -219,7 +207,6 @@ toolsets:\n   - file\n skills:\n   always_load:\n-    - kanban-worker\n     # for image-generator that drives ComfyUI locally:\n     # - comfyui\n env_required:","@@ -242,7 +229,6 @@ toolsets:\n   - file\n skills:\n   always_load:\n-    - kanban-worker\n     - songsee                         # spectrograms / audio analysis\n     # plus (depending on what the project needs):\n     # - songwriting-and-ai-music      (commissioning Suno tracks)","@@ -260,11 +246,11 @@ toolsets:\n   - video              # video_analyze — editor reviews assembled cuts natively\n   - vision             # vision_analyze — spot-check frames\n skills:\n-  always_load:\n-    - kanban-worker\n+  always_load: []\n ```\n \n-These are mostly ffmpeg-driven; no special skill needed beyond `kanban-worker`.\n+These are mostly ffmpeg-driven; no special skill needed (kanban guidance is\n+auto-injected into every kanban worker).\n For captioner add Whisper invocation patterns to the SOUL.md.\n \n ### reviewer / brand-cop","@@ -277,8 +263,7 @@ toolsets:\n   - video              # video_analyze — review full clips natively\n   - vision             # vision_analyze — review stills / exported frames\n skills:\n-  always_load:\n-    - kanban-worker\n+  always_load: []\n ```\n \n ## API key requirements"]},{"file":"optional-skills/creative/kanban-video-orchestrator/scripts/bootstrap_pipeline.py","hunks":["@@ -423,8 +423,6 @@ def render_soul_md(team_member: dict, plan: dict) -> str:\n             \"- **Decompose, route, comment, approve — that's the whole job.**\\n\"\n             \"- **Read TEAM.md** for the canonical task graph. Do not invent \"\n             \"new roles unless the brief truly demands it.\\n\"\n-            \"- **Load the `kanban-orchestrator` skill** for the deeper \"\n-            \"decomposition playbook beyond the auto-injected baseline.\\n\"\n         )\n \n     common_commands = ("]},{"file":"/dev/null","hunks":["@@ -1,214 +0,0 @@\n----\n-name: kanban-orchestrator\n-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.\n-version: 3.0.0\n-platforms: [linux, macos, windows]\n-environments: [kanban]\n-metadata:\n-  hermes:\n-    tags: [kanban, multi-agent, orchestration, routing]\n-    related_skills: [kanban-worker]\n----\n-\n-# Kanban Orchestrator — Decomposition Playbook\n-\n-> 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.\n-\n-## Profiles are user-configured — not a fixed roster\n-\n-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.\n-\n-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.\n-\n-**Step 0: discover available profiles before planning.**\n-\n-Use one of these:\n-\n-- `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.\n-- `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.\n-- **Just ask the user.** \"What profiles do you have set up?\" is a fine first turn when the goal needs more than one specialist.\n-\n-Cache the result in your working memory for the rest of the conversation. Re-asking every turn wastes a tool call.\n-\n-## When to use the board (vs. just doing the work)\n-\n-Create Kanban tasks when any of these are true:\n-\n-1. **Multiple specialists are needed.** Research + analysis + writing is three profiles.\n-2. **The work should survive a crash or restart.** Long-running, recurring, or important.\n-3. **The user might want to interject.** Human-in-the-loop at any step.\n-4. **Multiple subtasks can run in parallel.** Fan-out for speed.\n-5. **Review / iteration is expected.** A reviewer profile loops on drafter output.\n-6. **The audit trail matters.** Board rows persist in SQLite forever.\n-\n-If *none* of those apply — it's a small one-shot reasoning task — use `delegate_task` instead or answer the user directly.\n-\n-## The anti-temptation rules\n-\n-Your job description says \"route, don't execute.\" The rules that enforce that:\n-\n-- **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.\n-- **For any concrete task, create a Kanban task and assign it.** Every single time.\n-- **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.\n-- **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.\n-- **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.\n-- **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.\n-- **Decompose, route, and summarize — that's the whole job.**\n-\n-## Decomposition playbook\n-\n-### Step 1 — Understand the goal\n-\n-Ask clarifying questions if the goal is ambiguous. Cheap to ask; expensive to spawn the wrong fleet.\n-\n-### Step 2 — Sketch the task graph\n-\n-Before creating anything, draft the graph out loud (in your response to the user). Treat every concrete workstream as a candidate card:\n-\n-1. Extract the lanes from the request.\n-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.\n-3. Decide whether each lane is independent or gated by another lane.\n-4. Create independent lanes as parallel cards with no parent links.\n-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.\n-\n-Examples of prompts that should fan out (using placeholder profile names — substitute whatever exists on the user's setup):\n-\n-- \"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.\n-- \"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.\n-- \"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.\n-- \"Analyze this screenshot and find the related code\" → one card to a vision-capable profile for the visual analysis while another searches the codebase.\n-\n-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.\n-\n-Show the graph to the user before creating cards. Let them correct it — including which actual profile name should own each lane.\n-\n-### Step 3 — Create tasks and link\n-\n-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.\n-\n-```python\n-t1 = kanban_create(\n-    title=\"research: Postgres cost vs current\",\n-    assignee=\"<profile-A>\",  # whichever profile handles research on this setup\n-    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.\",\n-    tenant=os.environ.get(\"HERMES_TENANT\"),\n-)[\"task_id\"]\n-\n-t2 = kanban_create(\n-    title=\"research: Postgres performance vs current\",\n-    assignee=\"<profile-A>\",  # same profile, run in parallel\n-    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.\",\n-)[\"task_id\"]\n-\n-t3 = kanban_create(\n-    title=\"synthesize migration recommendation\",\n-    assignee=\"<profile-B>\",  # whichever profile does synthesis/analysis\n-    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.\",\n-    parents=[t1, t2],\n-)[\"task_id\"]\n-\n-t4 = kanban_create(\n-    title=\"draft decision memo\",\n-    assignee=\"<profile-C>\",  # whichever profile drafts user-facing prose\n-    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.\",\n-    parents=[t3],\n-)[\"task_id\"]\n-```\n-\n-`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.\n-\n-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.\n-\n-### Step 4 — Complete your own task\n-\n-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:\n-\n-```python\n-kanban_complete(\n-    summary=\"decomposed into T1-T4: 2 research lanes in parallel, 1 synthesis on their outputs, 1 prose draft on the recommendation\",\n-    metadata={\n-        \"task_graph\": {\n-            \"T1\": {\"assignee\": \"<profile-A>\", \"parents\": []},\n-            \"T2\": {\"assignee\": \"<profile-A>\", \"parents\": []},\n-            \"T3\": {\"assignee\": \"<profile-B>\", \"parents\": [\"T1\", \"T2\"]},\n-            \"T4\": {\"assignee\": \"<profile-C>\", \"parents\": [\"T3\"]},\n-        },\n-    },\n-)\n-```\n-\n-### Step 5 — Report back to the user\n-\n-Tell them what you created in plain prose, naming the actual profiles you used:\n-\n-> I've queued 4 tasks:\n-> - **T1** (`<profile-A>`): cost comparison\n-> - **T2** (`<profile-A>`): performance comparison, in parallel with T1\n-> - **T3** (`<profile-B>`): synthesizes T1 + T2 into a recommendation\n-> - **T4** (`<profile-C>`): turns T3 into a CTO memo\n->\n-> 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.\n-\n-## Common patterns\n-\n-**Fan-out + fan-in (research → synthesize):** N research-style cards with no parents, one synthesis card with all of them as parents.\n-\n-**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.\n-\n-**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.\n-\n-**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.\n-\n-**Human-in-the-loop:** Any task can `kanban_block()` to wait for input. Dispatcher respawns after `/unblock`. The comment thread carries the full context.\n-\n-## Pitfalls\n-\n-**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.\n-\n-**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.\n-\n-**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.\n-\n-**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.\n-\n-**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.\n-\n-**Argument order for links.** `kanban_link(parent_id=..., child_id=...)` — parent first. Mixing them up demotes the wrong task to `todo`.\n-\n-**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.\n-\n-**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.\n-\n-## Goal-mode cards (persistent workers)\n-\n-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:\n-\n-```python\n-kanban_create(\n-    title=\"Translate the full docs site to French\",\n-    body=\"Acceptance: every page translated, no English left, links intact.\",\n-    assignee=\"<translator-profile>\",\n-    goal_mode=True,        # judge re-checks the card after each turn\n-    goal_max_turns=15,     # optional budget (default 20)\n-)[\"task_id\"]\n-```\n-\n-How it behaves:\n-- After each worker turn, an auxiliary judge evaluates the worker's response against the card's **title + body** (treated as the acceptance criteria).\n-- Not done + budget remains → the worker keeps going **in the same session** (full context retained — not a fresh respawn).\n-- Worker calls `kanban_complete`/`kanban_block` itself → loop stops, normal lifecycle.\n-- Budget exhausted without completion → the card is **blocked** for human review (sticky), never a silent exit.\n-\n-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.\n-\n-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.\"\n-\n-## Recovering stuck workers\n-\n-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:\n-\n-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.\n-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.\n-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.\n-\n-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."]},{"file":"/dev/null","hunks":["@@ -1,214 +0,0 @@\n----\n-name: kanban-worker\n-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.\n-version: 2.0.0\n-platforms: [linux, macos, windows]\n-environments: [kanban]\n-metadata:\n-  hermes:\n-    tags: [kanban, multi-agent, collaboration, workflow, pitfalls]\n-    related_skills: [kanban-orchestrator]\n----\n-\n-# Kanban Worker — Pitfalls and Examples\n-\n-> 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.\n-\n-## Workspace handling\n-\n-Your workspace kind determines how you should behave inside `$HERMES_KANBAN_WORKSPACE`:\n-\n-| Kind | What it is | How to work |\n-|---|---|---|\n-| `scratch` | Fresh tmp dir, yours alone | Read/write freely; it gets GC'd when the task is archived. |\n-| `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). |\n-| `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. |\n-\n-## Tenant isolation\n-\n-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:\n-\n-- Good: `business-a: Acme is our biggest customer`\n-- Bad (leaks): `Acme is our biggest customer`\n-\n-## Good summary + metadata shapes\n-\n-The `kanban_complete(summary=..., metadata=...)` handoff is how downstream workers read what you did. Patterns that work:\n-\n-**Coding task:**\n-```python\n-kanban_complete(\n-    summary=\"shipped rate limiter — token bucket, keys on user_id with IP fallback, 14 tests pass\",\n-    metadata={\n-        \"changed_files\": [\"rate_limiter.py\", \"tests/test_rate_limiter.py\"],\n-        \"tests_run\": 14,\n-        \"tests_passed\": 14,\n-        \"decisions\": [\"user_id primary, IP fallback for unauthenticated requests\"],\n-    },\n-)\n-```\n-\n-**Coding task that needs human review (review-required):**\n-\n-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.\n-\n-```python\n-import json\n-\n-kanban_comment(\n-    body=\"review-required handoff:\\n\" + json.dumps({\n-        \"changed_files\": [\"rate_limiter.py\", \"tests/test_rate_limiter.py\"],\n-        \"tests_run\": 14,\n-        \"tests_passed\": 14,\n-        \"diff_path\": \"/path/to/worktree\",  # or PR url if pushed\n-        \"decisions\": [\"user_id primary, IP fallback for unauthenticated requests\"],\n-    }, indent=2),\n-)\n-kanban_block(\n-    reason=\"review-required: rate limiter shipped, 14/14 tests pass — needs eyes on the user_id/IP fallback choice before merging\",\n-)\n-```\n-\n-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.\n-\n-**Research task:**\n-```python\n-kanban_complete(\n-    summary=\"3 competing libraries reviewed; vLLM wins on throughput, SGLang on latency, Tensorrt-LLM on memory efficiency\",\n-    metadata={\n-        \"sources_read\": 12,\n-        \"recommendation\": \"vLLM\",\n-        \"benchmarks\": {\"vllm\": 1.0, \"sglang\": 0.87, \"trtllm\": 0.72},\n-    },\n-)\n-```\n-\n-**Review task:**\n-```python\n-kanban_complete(\n-    summary=\"reviewed PR #123; 2 blocking issues found (SQL injection in /search, missing CSRF on /settings)\",\n-    metadata={\n-        \"pr_number\": 123,\n-        \"findings\": [\n-            {\"severity\": \"critical\", \"file\": \"api/search.py\", \"line\": 42, \"issue\": \"raw SQL concat\"},\n-            {\"severity\": \"high\", \"file\": \"api/settings.py\", \"issue\": \"missing CSRF middleware\"},\n-        ],\n-        \"approved\": False,\n-    },\n-)\n-```\n-\n-Shape `metadata` so downstream parsers (reviewers, aggregators, schedulers) can use it without re-reading your prose.\n-\n-## Shipping deliverables (`artifacts=[...]`)\n-\n-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.\n-\n-```python\n-kanban_complete(\n-    summary=\"Q3 revenue analysis: 14% QoQ growth, EMEA the laggard. Chart + full PDF attached.\",\n-    artifacts=[\"/tmp/q3-revenue.png\", \"/tmp/q3-report.pdf\"],\n-    metadata={\"rows_analyzed\": 48000, \"growth_qoq\": 0.14},\n-)\n-```\n-\n-Images and video embed inline; PDFs, docx, csv/xlsx/json/yaml, pptx, zip/tar/gz, audio, and html upload as files. Rules:\n-\n-- **Absolute paths only**, and the file must still exist when you complete — don't point at a scratch file you already deleted.\n-- **Only real deliverables.** Skip intermediate logs, scratch files, and inputs the human already has.\n-- `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.\n-- A bare string is auto-promoted to a one-element list, and it merges with any pre-existing `metadata.artifacts` without dupes.\n-\n-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.\n-\n-## Claiming cards you actually created\n-\n-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.**\n-\n-```python\n-# GOOD — capture return values, then claim them.\n-c1 = kanban_create(title=\"remediate SQL injection\", assignee=\"security-worker\")\n-c2 = kanban_create(title=\"fix CSRF middleware\", assignee=\"web-worker\")\n-\n-kanban_complete(\n-    summary=\"Review done; spawned remediations for both findings.\",\n-    metadata={\"pr_number\": 123, \"approved\": False},\n-    created_cards=[c1[\"task_id\"], c2[\"task_id\"]],\n-)\n-```\n-\n-```python\n-# BAD — claiming ids you don't have captured return values for.\n-kanban_complete(\n-    summary=\"Created remediation cards t_a1b2c3d4, t_deadbeef\",  # hallucinated\n-    created_cards=[\"t_a1b2c3d4\", \"t_deadbeef\"],                   # → gate rejects\n-)\n-```\n-\n-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.\n-\n-## Block reasons that get answered fast\n-\n-Bad: `\"stuck\"` — the human has no context.\n-\n-Good: one sentence naming the specific decision you need. Leave longer context as a comment instead.\n-\n-```python\n-kanban_comment(\n-    task_id=os.environ[\"HERMES_KANBAN_TASK\"],\n-    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.\",\n-)\n-kanban_block(reason=\"Rate limit key choice: IP (simple, NAT-unsafe) or user_id (requires auth, skips anonymous endpoints)?\")\n-```\n-\n-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.\n-\n-## Heartbeats worth sending\n-\n-Good heartbeats name progress: `\"epoch 12/50, loss 0.31\"`, `\"scanned 1.2M/2.4M rows\"`, `\"uploaded 47/120 videos\"`.\n-\n-Bad heartbeats: `\"still working\"`, empty notes, sub-second intervals. Every few minutes max; skip entirely for tasks under ~2 minutes.\n-\n-## Retry scenarios\n-\n-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:\n-\n-- `outcome: \"timed_out\"` — the previous attempt hit `max_runtime_seconds`. You may need to chunk the work or shorten it.\n-- `outcome: \"crashed\"` — OOM or segfault. Reduce memory footprint.\n-- `outcome: \"spawn_failed\"` + `error: \"...\"` — usually a profile config issue (missing credential, bad PATH). Ask the human via `kanban_block` instead of retrying blindly.\n-- `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.\n-- `outcome: \"blocked\"` — a previous attempt blocked; the unblock comment should be in the thread by now.\n-\n-## Notification routing\n-\n-You can configure the gateway to receive cross-profile Kanban task notifications by adding `notification_sources` to `~/.hermes/config.yaml`.\n-- `notification_sources: ['*']` accepts subscriptions from all profiles.\n-- `notification_sources: ['default', 'zilor-ppt']` or `\"default,zilor-ppt\"` restricts subscriptions to specified profiles.\n-- Omitting the key keeps the default behavior (profile isolation).\n-\n-## Do NOT\n-\n-- 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.\n-- 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.\n-- Modify files outside `$HERMES_KANBAN_WORKSPACE` unless the task body says to.\n-- Create follow-up tasks assigned to yourself — assign to the right specialist.\n-- Complete a task you didn't actually finish. Block it instead.\n-\n-## Pitfalls\n-\n-**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.\n-\n-**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.\n-\n-**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.\n-\n-## CLI fallback (for scripting)\n-\n-Every tool has a CLI equivalent for human operators and scripts:\n-- `kanban_show` ↔ `hermes kanban show <id> --json`\n-- `kanban_complete` ↔ `hermes kanban complete <id> --summary \"...\" --metadata '{...}'`\n-- `kanban_block` ↔ `hermes kanban block <id> \"reason\"`\n-- `kanban_create` ↔ `hermes kanban create \"title\" --assignee <profile> [--parent <id>]`\n-- etc.\n-\n-Use the tools from inside an agent; the CLI exists for the human at the terminal."]},{"file":"tests/hermes_cli/test_kanban_core_functionality.py","hunks":["@@ -2703,20 +2703,17 @@ def test_build_worker_context_caps_huge_summary(kanban_home):\n         conn.close()\n \n \n-def test_default_spawn_auto_loads_kanban_worker_skill(kanban_home, monkeypatch):\n-    \"\"\"The dispatcher's _default_spawn must include --skills kanban-worker\n-    in its argv so every worker loads the skill automatically, even if\n-    the profile hasn't wired it into its default skills config.\n+def test_default_spawn_does_not_auto_load_any_skill(kanban_home, monkeypatch):\n+    \"\"\"The dispatcher no longer auto-loads a bundled kanban skill.\n+\n+    The kanban lifecycle (formerly the kanban-worker/kanban-orchestrator\n+    skills) is now injected into every worker's system prompt via\n+    KANBAN_GUIDANCE, so _default_spawn must NOT append a `--skills` flag\n+    when the task carries no per-task skills.\n \n     We intercept Popen to capture the argv without actually spawning a\n     hermes subprocess (which would hang trying to call an LLM).\n     \"\"\"\n-    # Pretend the bundled kanban-worker skill resolves for this isolated\n-    # HERMES_HOME — the fixture creates an empty tmpdir without the\n-    # devops/kanban-worker tree, and _default_spawn gates the --skills\n-    # flag on actual resolvability.\n-    monkeypatch.setattr(kb, \"_kanban_worker_skill_available\", lambda _h: True)\n-\n     captured = {}\n \n     class FakeProc:","@@ -2742,10 +2739,8 @@ def fake_popen(cmd, **kwargs):\n         conn.close()\n \n     cmd = captured[\"cmd\"]\n-    assert \"--skills\" in cmd, f\"spawn argv missing --skills: {cmd}\"\n-    idx = cmd.index(\"--skills\")\n-    assert cmd[idx + 1] == \"kanban-worker\", (\n-        f\"expected 'kanban-worker', got {cmd[idx + 1]!r}\"\n+    assert \"--skills\" not in cmd, (\n+        f\"spawn argv should not auto-load any skill: {cmd}\"\n     )\n     assert \"--accept-hooks\" in cmd, f\"spawn argv missing --accept-hooks: {cmd}\"\n     assert cmd.index(\"--accept-hooks\") < cmd.index(\"chat\"), (","@@ -2985,8 +2980,7 @@ def test_create_task_skills_lists_all_toolset_typos(kanban_home):\n \n def test_default_spawn_appends_per_task_skills(kanban_home, monkeypatch):\n     \"\"\"Dispatcher argv must carry one `--skills X` pair per task skill,\n-    in addition to the built-in kanban-worker.\"\"\"\n-    monkeypatch.setattr(kb, \"_kanban_worker_skill_available\", lambda _h: True)\n+    in declared order. No skill is auto-loaded anymore.\"\"\"\n     captured = {}\n \n     class FakeProc:","@@ -3019,10 +3013,8 @@ def fake_popen(cmd, **kwargs):\n     for i, tok in enumerate(cmd):\n         if tok == \"--skills\" and i + 1 < len(cmd):\n             skill_names.append(cmd[i + 1])\n-    # kanban-worker first (built-in), then per-task extras in order.\n-    assert skill_names[0] == \"kanban-worker\", skill_names\n-    assert \"translation\" in skill_names\n-    assert \"github-code-review\" in skill_names\n+    # Only the per-task skills, in declared order — nothing auto-loaded.\n+    assert skill_names == [\"translation\", \"github-code-review\"], skill_names\n     # --skills must appear BEFORE the `chat` subcommand so argparse\n     # attaches them to the top-level parser, not the subcommand.\n     chat_idx = cmd.index(\"chat\")","@@ -3034,9 +3026,9 @@ def fake_popen(cmd, **kwargs):\n     )\n \n \n-def test_default_spawn_dedupes_kanban_worker_from_task_skills(kanban_home, monkeypatch):\n-    \"\"\"If a task explicitly lists 'kanban-worker', we don't double-pass it.\"\"\"\n-    monkeypatch.setattr(kb, \"_kanban_worker_skill_available\", lambda _h: True)\n+def test_default_spawn_passes_task_skills_verbatim(kanban_home, monkeypatch):\n+    \"\"\"Per-task skills are passed through verbatim — there is no built-in\n+    kanban skill to dedupe against anymore.\"\"\"\n     captured = {}\n \n     class FakeProc:","@@ -3052,7 +3044,7 @@ def fake_popen(cmd, **kwargs):\n     try:\n         tid = kb.create_task(\n             conn, title=\"dup\", assignee=\"x\",\n-            skills=[\"kanban-worker\", \"translation\"],\n+            skills=[\"translation\", \"github-code-review\"],\n         )\n         task = kb.get_task(conn, tid)\n         workspace = kb.resolve_workspace(task)","@@ -3061,12 +3053,14 @@ def fake_popen(cmd, **kwargs):\n         conn.close()\n \n     cmd = captured[\"cmd\"]\n-    worker_pairs = [\n-        i for i, tok in enumerate(cmd)\n-        if tok == \"--skills\" and i + 1 < len(cmd) and cmd[i + 1] == \"kanban-worker\"\n+    skill_names = [\n+        cmd[i + 1]\n+        for i, tok in enumerate(cmd)\n+        if tok == \"--skills\" and i + 1 < len(cmd)\n     ]\n-    assert len(worker_pairs) == 1, (\n-        f\"kanban-worker appeared {len(worker_pairs)} times in argv: {cmd}\"\n+    # Exactly the task's skills, once each, in order — no auto-loaded extras.\n+    assert skill_names == [\"translation\", \"github-code-review\"], (\n+        f\"unexpected --skills in argv: {cmd}\"\n     )\n \n "]},{"file":"tests/hermes_cli/test_kanban_goal_mode.py","hunks":["@@ -132,8 +132,6 @@ def _fake_popen(cmd, **kwargs):\n         return _FakeProc()\n \n     monkeypatch.setattr(\"subprocess.Popen\", _fake_popen)\n-    # Avoid the kanban-worker skill probe touching the real skills dir.\n-    monkeypatch.setattr(kb, \"_kanban_worker_skill_available\", lambda home: False)\n \n     with kb.connect() as conn:\n         tid = kb.create_task(","@@ -162,7 +160,6 @@ def _fake_popen(cmd, **kwargs):\n         return _FakeProc()\n \n     monkeypatch.setattr(\"subprocess.Popen\", _fake_popen)\n-    monkeypatch.setattr(kb, \"_kanban_worker_skill_available\", lambda home: False)\n \n     with kb.connect() as conn:\n         tid = kb.create_task(conn, title=\"plain\", assignee=\"default\")"]},{"file":"tests/tools/test_kanban_tools.py","hunks":["@@ -1224,8 +1224,16 @@ def test_kanban_guidance_in_worker_prompt(monkeypatch, tmp_path):\n \n \n def test_kanban_guidance_prompt_size_bounded(monkeypatch, tmp_path):\n-    \"\"\"Sanity: the guidance block is under 4 KB so it doesn't blow\n-    up the cached prompt.\"\"\"\n+    \"\"\"Sanity: the guidance block stays lean so it doesn't blow up the\n+    cached prompt.\n+\n+    The ceiling guards against unbounded growth, not against any growth.\n+    The block absorbed the load-bearing worker/orchestrator reference\n+    details (workspace kinds, deliverable artifacts, created-card claims,\n+    profile discovery) when the standalone kanban-worker / kanban-orchestrator\n+    skills were removed and folded into this always-injected guidance, so the\n+    ceiling is sized to fit that content with a little headroom.\n+    \"\"\"\n     monkeypatch.setenv(\"HERMES_KANBAN_TASK\", \"t_fake\")\n     home = tmp_path / \".hermes\"\n     home.mkdir()","@@ -1234,7 +1242,7 @@ def test_kanban_guidance_prompt_size_bounded(monkeypatch, tmp_path):\n     monkeypatch.setattr(_P, \"home\", lambda: tmp_path)\n \n     from agent.prompt_builder import KANBAN_GUIDANCE\n-    assert 1_500 < len(KANBAN_GUIDANCE) < 4_096, (\n+    assert 1_500 < len(KANBAN_GUIDANCE) < 5_500, (\n         f\"KANBAN_GUIDANCE is {len(KANBAN_GUIDANCE)} chars — too short (missing?) or too long\"\n     )\n "]},{"file":"tools/kanban_tools.py","hunks":["@@ -1382,8 +1382,8 @@ def _board_schema_prop() -> dict[str, str]:\n                 \"items\": {\"type\": \"string\"},\n                 \"description\": (\n                     \"Skill names to force-load into the dispatched \"\n-                    \"worker (in addition to the built-in kanban-worker \"\n-                    \"skill). Use this to pin a task to a specialist \"\n+                    \"worker. The kanban lifecycle is already injected \"\n+                    \"automatically; use this to pin a task to a specialist \"\n                     \"context — e.g. ['translation'] for a translation \"\n                     \"task, ['github-code-review'] for a reviewer task. \"\n                     \"The names must match skills installed on the \""]},{"file":"website/docs/reference/skills-catalog.md","hunks":["@@ -62,8 +62,7 @@ If a skill is missing from this list but present in the repo, the catalog is reg\n \n | Skill | Description | Path |\n |-------|-------------|------|\n-| [`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` |\n-| [`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` |\n+\n \n ## dogfood\n "]},{"file":"website/docs/user-guide/features/kanban-worker-lanes.md","hunks":["@@ -7,7 +7,7 @@ This page is the contract. It exists for two audiences:\n - **Operators** picking which lanes to wire into a board (which profiles to create, which assignees to use).\n - **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).\n \n-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.\n+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)).\n \n ## The hierarchy\n ","@@ -64,7 +64,7 @@ For most code-changing tasks, the work isn't truly *done* the moment the worker\n - **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.\n - **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.\n \n-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.\n+The injected `KANBAN_GUIDANCE` covers both `kanban_complete` (truly terminal tasks — typo fixes, docs changes, research writeups) and the `review-required` block pattern.\n \n ## Logs and audit trail\n ","@@ -80,9 +80,9 @@ The dashboard renders run history with summaries, metadata blocks, and exit-stat\n \n ### Hermes profile lane (default)\n \n-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.\n+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.\n \n-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).\n+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`).\n \n ### Orchestrator profile lane\n ","@@ -110,5 +110,4 @@ So lane authors don't have to reimplement these:\n \n - [Kanban overview](./kanban) — the user-facing intro.\n - [Kanban tutorial](./kanban-tutorial) — walkthrough with the dashboard open.\n-- [`kanban-worker`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-worker/SKILL.md) — the skill the worker process loads.\n-- [`kanban-orchestrator`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-orchestrator/SKILL.md) — the orchestrator side.\n+- [`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."]},{"file":"website/docs/user-guide/features/kanban.md","hunks":["@@ -310,7 +310,7 @@ kanban_create(\n kanban_complete(summary=\"decomposed into 2 research tasks + 1 writer; linked dependencies\")\n ```\n \n-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.\n+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.\n \n ### Why tools instead of shelling to `hermes kanban`\n ","@@ -322,7 +322,7 @@ Three reasons:\n \n **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.\n \n-The `kanban-worker` and `kanban-orchestrator` skills teach the model which tool to call when and in what order.\n+The auto-injected kanban guidance teaches the model which tool to call when and in what order.\n \n ### Recommended handoff evidence\n ","@@ -358,9 +358,9 @@ Keep secrets, raw logs, tokens, OAuth material, and unrelated transcripts out of\n tests, say so explicitly in `summary` and use `metadata` for the evidence that\n does exist, such as source URLs, issue ids, or manual review steps.\n \n-### The worker skill\n+### The worker lifecycle\n \n-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:\n+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:\n \n 1. On spawn, call `kanban_show()` to read title + body + parent handoffs + prior attempts + full comment thread.\n 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\n of respawning it into the same loop. This usually means the model wrote a\n plain-text answer and exited without using the Kanban tool surface.\n \n-`kanban-worker` is a bundled skill, synced into every profile during install and\n-update — there is no separate Skills Hub install step. Verify it is present in\n-whichever profile you use for kanban workers (`researcher`, `writer`, `ops`,\n-etc.):\n-\n-```bash\n-hermes -p <your-worker-profile> skills list | grep kanban-worker\n-```\n-\n-If the bundled copy is missing, restore it for that profile:\n-\n-```bash\n-hermes -p <your-worker-profile> skills reset kanban-worker --restore\n-```\n-\n-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.\n+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.\n \n ### Pinning extra skills to a specific task\n ","@@ -426,7 +411,7 @@ hermes kanban create \"audit auth flow\" \\\n \n **From the dashboard**, type the skills comma-separated into the **skills** field of the inline create form.\n \n-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.\n+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.\n \n ### Goal-mode cards (`--goal`)\n ","@@ -442,9 +427,9 @@ hermes kanban create \"Translate the docs site to French\" \\\n \n 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**.\n \n-### The orchestrator skill\n+### How the orchestrator behaves\n \n-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`.\n+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.\n \n A canonical orchestrator turn (two parallel researchers handing off to a writer):\n ","@@ -465,19 +450,7 @@ kanban_complete(\n )\n ```\n \n-`kanban-orchestrator` is a bundled skill. It is synced into each profile during\n-install and update, so there is no separate Skills Hub install step. Verify it is\n-present in your orchestrator profile:\n-\n-```bash\n-hermes -p orchestrator skills list | grep kanban-orchestrator\n-```\n-\n-If the bundled copy is missing, restore it for that profile:\n-\n-```bash\n-hermes -p orchestrator skills reset kanban-orchestrator --restore\n-```\n+The orchestrator guidance ships in the worker's system prompt automatically — there is nothing to install or sync per profile.\n \n 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.\n "]},{"file":"website/docs/user-guide/skills/bundled/autonomous-ai-agents/autonomous-ai-agents-kanban-codex-lane.md","hunks":["@@ -20,7 +20,7 @@ Use when a Hermes Kanban worker wants to run Codex CLI as an isolated implementa\n | Author | Hermes Agent |\n | License | MIT |\n | Tags | `kanban`, `codex`, `worktrees`, `autonomous-agents`, `prediction-market-bot` |\n-| 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) |\n+| 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) |\n \n ## Reference: full SKILL.md\n "]},{"file":"/dev/null","hunks":["@@ -1,231 +0,0 @@\n----\n-title: \"Kanban Orchestrator\"\n-sidebar_label: \"Kanban Orchestrator\"\n-description: \"Decomposition playbook + anti-temptation rules for an orchestrator profile routing work through Kanban\"\n----\n-\n-{/* 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. */}\n-\n-# Kanban Orchestrator\n-\n-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.\n-\n-## Skill metadata\n-\n-| | |\n-|---|---|\n-| Source | Bundled (installed by default) |\n-| Path | `skills/devops/kanban-orchestrator` |\n-| Version | `3.0.0` |\n-| Platforms | linux, macos, windows |\n-| Tags | `kanban`, `multi-agent`, `orchestration`, `routing` |\n-| Related skills | [`kanban-worker`](/docs/user-guide/skills/bundled/devops/devops-kanban-worker) |\n-\n-## Reference: full SKILL.md\n-\n-:::info\n-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.\n-:::\n-\n-# Kanban Orchestrator — Decomposition Playbook\n-\n-> 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.\n-\n-## Profiles are user-configured — not a fixed roster\n-\n-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.\n-\n-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.\n-\n-**Step 0: discover available profiles before planning.**\n-\n-Use one of these:\n-\n-- `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.\n-- `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.\n-- **Just ask the user.** \"What profiles do you have set up?\" is a fine first turn when the goal needs more than one specialist.\n-\n-Cache the result in your working memory for the rest of the conversation. Re-asking every turn wastes a tool call.\n-\n-## When to use the board (vs. just doing the work)\n-\n-Create Kanban tasks when any of these are true:\n-\n-1. **Multiple specialists are needed.** Research + analysis + writing is three profiles.\n-2. **The work should survive a crash or restart.** Long-running, recurring, or important.\n-3. **The user might want to interject.** Human-in-the-loop at any step.\n-4. **Multiple subtasks can run in parallel.** Fan-out for speed.\n-5. **Review / iteration is expected.** A reviewer profile loops on drafter output.\n-6. **The audit trail matters.** Board rows persist in SQLite forever.\n-\n-If *none* of those apply — it's a small one-shot reasoning task — use `delegate_task` instead or answer the user directly.\n-\n-## The anti-temptation rules\n-\n-Your job description says \"route, don't execute.\" The rules that enforce that:\n-\n-- **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.\n-- **For any concrete task, create a Kanban task and assign it.** Every single time.\n-- **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.\n-- **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.\n-- **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.\n-- **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.\n-- **Decompose, route, and summarize — that's the whole job.**\n-\n-## Decomposition playbook\n-\n-### Step 1 — Understand the goal\n-\n-Ask clarifying questions if the goal is ambiguous. Cheap to ask; expensive to spawn the wrong fleet.\n-\n-### Step 2 — Sketch the task graph\n-\n-Before creating anything, draft the graph out loud (in your response to the user). Treat every concrete workstream as a candidate card:\n-\n-1. Extract the lanes from the request.\n-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.\n-3. Decide whether each lane is independent or gated by another lane.\n-4. Create independent lanes as parallel cards with no parent links.\n-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.\n-\n-Examples of prompts that should fan out (using placeholder profile names — substitute whatever exists on the user's setup):\n-\n-- \"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.\n-- \"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.\n-- \"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.\n-- \"Analyze this screenshot and find the related code\" → one card to a vision-capable profile for the visual analysis while another searches the codebase.\n-\n-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.\n-\n-Show the graph to the user before creating cards. Let them correct it — including which actual profile name should own each lane.\n-\n-### Step 3 — Create tasks and link\n-\n-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.\n-\n-```python\n-t1 = kanban_create(\n-    title=\"research: Postgres cost vs current\",\n-    assignee=\"<profile-A>\",  # whichever profile handles research on this setup\n-    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.\",\n-    tenant=os.environ.get(\"HERMES_TENANT\"),\n-)[\"task_id\"]\n-\n-t2 = kanban_create(\n-    title=\"research: Postgres performance vs current\",\n-    assignee=\"<profile-A>\",  # same profile, run in parallel\n-    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.\",\n-)[\"task_id\"]\n-\n-t3 = kanban_create(\n-    title=\"synthesize migration recommendation\",\n-    assignee=\"<profile-B>\",  # whichever profile does synthesis/analysis\n-    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.\",\n-    parents=[t1, t2],\n-)[\"task_id\"]\n-\n-t4 = kanban_create(\n-    title=\"draft decision memo\",\n-    assignee=\"<profile-C>\",  # whichever profile drafts user-facing prose\n-    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.\",\n-    parents=[t3],\n-)[\"task_id\"]\n-```\n-\n-`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.\n-\n-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.\n-\n-### Step 4 — Complete your own task\n-\n-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:\n-\n-```python\n-kanban_complete(\n-    summary=\"decomposed into T1-T4: 2 research lanes in parallel, 1 synthesis on their outputs, 1 prose draft on the recommendation\",\n-    metadata={\n-        \"task_graph\": {\n-            \"T1\": {\"assignee\": \"<profile-A>\", \"parents\": []},\n-            \"T2\": {\"assignee\": \"<profile-A>\", \"parents\": []},\n-            \"T3\": {\"assignee\": \"<profile-B>\", \"parents\": [\"T1\", \"T2\"]},\n-            \"T4\": {\"assignee\": \"<profile-C>\", \"parents\": [\"T3\"]},\n-        },\n-    },\n-)\n-```\n-\n-### Step 5 — Report back to the user\n-\n-Tell them what you created in plain prose, naming the actual profiles you used:\n-\n-> I've queued 4 tasks:\n-> - **T1** (`<profile-A>`): cost comparison\n-> - **T2** (`<profile-A>`): performance comparison, in parallel with T1\n-> - **T3** (`<profile-B>`): synthesizes T1 + T2 into a recommendation\n-> - **T4** (`<profile-C>`): turns T3 into a CTO memo\n->\n-> 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.\n-\n-## Common patterns\n-\n-**Fan-out + fan-in (research → synthesize):** N research-style cards with no parents, one synthesis card with all of them as parents.\n-\n-**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.\n-\n-**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.\n-\n-**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.\n-\n-**Human-in-the-loop:** Any task can `kanban_block()` to wait for input. Dispatcher respawns after `/unblock`. The comment thread carries the full context.\n-\n-## Pitfalls\n-\n-**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.\n-\n-**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.\n-\n-**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.\n-\n-**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.\n-\n-**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.\n-\n-**Argument order for links.** `kanban_link(parent_id=..., child_id=...)` — parent first. Mixing them up demotes the wrong task to `todo`.\n-\n-**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.\n-\n-**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.\n-\n-## Goal-mode cards (persistent workers)\n-\n-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:\n-\n-```python\n-kanban_create(\n-    title=\"Translate the full docs site to French\",\n-    body=\"Acceptance: every page translated, no English left, links intact.\",\n-    assignee=\"<translator-profile>\",\n-    goal_mode=True,        # judge re-checks the card after each turn\n-    goal_max_turns=15,     # optional budget (default 20)\n-)[\"task_id\"]\n-```\n-\n-How it behaves:\n-- After each worker turn, an auxiliary judge evaluates the worker's response against the card's **title + body** (treated as the acceptance criteria).\n-- Not done + budget remains → the worker keeps going **in the same session** (full context retained — not a fresh respawn).\n-- Worker calls `kanban_complete`/`kanban_block` itself → loop stops, normal lifecycle.\n-- Budget exhausted without completion → the card is **blocked** for human review (sticky), never a silent exit.\n-\n-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.\n-\n-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.\"\n-\n-## Recovering stuck workers\n-\n-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:\n-\n-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.\n-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.\n-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.\n-\n-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."]},{"file":"/dev/null","hunks":["@@ -1,210 +0,0 @@\n----\n-title: \"Kanban Worker — Pitfalls, examples, and edge cases for Hermes Kanban workers\"\n-sidebar_label: \"Kanban Worker\"\n-description: \"Pitfalls, examples, and edge cases for Hermes Kanban workers\"\n----\n-\n-{/* 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. */}\n-\n-# Kanban Worker\n-\n-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.\n-\n-## Skill metadata\n-\n-| | |\n-|---|---|\n-| Source | Bundled (installed by default) |\n-| Path | `skills/devops/kanban-worker` |\n-| Version | `2.0.0` |\n-| Platforms | linux, macos, windows |\n-| Tags | `kanban`, `multi-agent`, `collaboration`, `workflow`, `pitfalls` |\n-| Related skills | [`kanban-orchestrator`](/docs/user-guide/skills/bundled/devops/devops-kanban-orchestrator) |\n-\n-## Reference: full SKILL.md\n-\n-:::info\n-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.\n-:::\n-\n-# Kanban Worker — Pitfalls and Examples\n-\n-> 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.\n-\n-## Workspace handling\n-\n-Your workspace kind determines how you should behave inside `$HERMES_KANBAN_WORKSPACE`:\n-\n-| Kind | What it is | How to work |\n-|---|---|---|\n-| `scratch` | Fresh tmp dir, yours alone | Read/write freely; it gets GC'd when the task is archived. |\n-| `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). |\n-| `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. |\n-\n-## Tenant isolation\n-\n-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:\n-\n-- Good: `business-a: Acme is our biggest customer`\n-- Bad (leaks): `Acme is our biggest customer`\n-\n-## Good summary + metadata shapes\n-\n-The `kanban_complete(summary=..., metadata=...)` handoff is how downstream workers read what you did. Patterns that work:\n-\n-**Coding task:**\n-```python\n-kanban_complete(\n-    summary=\"shipped rate limiter — token bucket, keys on user_id with IP fallback, 14 tests pass\",\n-    metadata={\n-        \"changed_files\": [\"rate_limiter.py\", \"tests/test_rate_limiter.py\"],\n-        \"tests_run\": 14,\n-        \"tests_passed\": 14,\n-        \"decisions\": [\"user_id primary, IP fallback for unauthenticated requests\"],\n-    },\n-)\n-```\n-\n-**Coding task that needs human review (review-required):**\n-\n-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.\n-\n-```python\n-import json\n-\n-kanban_comment(\n-    body=\"review-required handoff:\\n\" + json.dumps({\n-        \"changed_files\": [\"rate_limiter.py\", \"tests/test_rate_limiter.py\"],\n-        \"tests_run\": 14,\n-        \"tests_passed\": 14,\n-        \"diff_path\": \"/path/to/worktree\",  # or PR url if pushed\n-        \"decisions\": [\"user_id primary, IP fallback for unauthenticated requests\"],\n-    }, indent=2),\n-)\n-kanban_block(\n-    reason=\"review-required: rate limiter shipped, 14/14 tests pass — needs eyes on the user_id/IP fallback choice before merging\",\n-)\n-```\n-\n-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.\n-\n-**Research task:**\n-```python\n-kanban_complete(\n-    summary=\"3 competing libraries reviewed; vLLM wins on throughput, SGLang on latency, Tensorrt-LLM on memory efficiency\",\n-    metadata={\n-        \"sources_read\": 12,\n-        \"recommendation\": \"vLLM\",\n-        \"benchmarks\": {\"vllm\": 1.0, \"sglang\": 0.87, \"trtllm\": 0.72},\n-    },\n-)\n-```\n-\n-**Review task:**\n-```python\n-kanban_complete(\n-    summary=\"reviewed PR #123; 2 blocking issues found (SQL injection in /search, missing CSRF on /settings)\",\n-    metadata={\n-        \"pr_number\": 123,\n-        \"findings\": [\n-            {\"severity\": \"critical\", \"file\": \"api/search.py\", \"line\": 42, \"issue\": \"raw SQL concat\"},\n-            {\"severity\": \"high\", \"file\": \"api/settings.py\", \"issue\": \"missing CSRF middleware\"},\n-        ],\n-        \"approved\": False,\n-    },\n-)\n-```\n-\n-Shape `metadata` so downstream parsers (reviewers, aggregators, schedulers) can use it without re-reading your prose.\n-\n-## Claiming cards you actually created\n-\n-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.**\n-\n-```python\n-# GOOD — capture return values, then claim them.\n-c1 = kanban_create(title=\"remediate SQL injection\", assignee=\"security-worker\")\n-c2 = kanban_create(title=\"fix CSRF middleware\", assignee=\"web-worker\")\n-\n-kanban_complete(\n-    summary=\"Review done; spawned remediations for both findings.\",\n-    metadata={\"pr_number\": 123, \"approved\": False},\n-    created_cards=[c1[\"task_id\"], c2[\"task_id\"]],\n-)\n-```\n-\n-```python\n-# BAD — claiming ids you don't have captured return values for.\n-kanban_complete(\n-    summary=\"Created remediation cards t_a1b2c3d4, t_deadbeef\",  # hallucinated\n-    created_cards=[\"t_a1b2c3d4\", \"t_deadbeef\"],                   # → gate rejects\n-)\n-```\n-\n-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.\n-\n-## Block reasons that get answered fast\n-\n-Bad: `\"stuck\"` — the human has no context.\n-\n-Good: one sentence naming the specific decision you need. Leave longer context as a comment instead.\n-\n-```python\n-kanban_comment(\n-    task_id=os.environ[\"HERMES_KANBAN_TASK\"],\n-    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.\",\n-)\n-kanban_block(reason=\"Rate limit key choice: IP (simple, NAT-unsafe) or user_id (requires auth, skips anonymous endpoints)?\")\n-```\n-\n-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.\n-\n-## Heartbeats worth sending\n-\n-Good heartbeats name progress: `\"epoch 12/50, loss 0.31\"`, `\"scanned 1.2M/2.4M rows\"`, `\"uploaded 47/120 videos\"`.\n-\n-Bad heartbeats: `\"still working\"`, empty notes, sub-second intervals. Every few minutes max; skip entirely for tasks under ~2 minutes.\n-\n-## Retry scenarios\n-\n-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:\n-\n-- `outcome: \"timed_out\"` — the previous attempt hit `max_runtime_seconds`. You may need to chunk the work or shorten it.\n-- `outcome: \"crashed\"` — OOM or segfault. Reduce memory footprint.\n-- `outcome: \"spawn_failed\"` + `error: \"...\"` — usually a profile config issue (missing credential, bad PATH). Ask the human via `kanban_block` instead of retrying blindly.\n-- `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.\n-- `outcome: \"blocked\"` — a previous attempt blocked; the unblock comment should be in the thread by now.\n-\n-## Notification routing\n-\n-You can configure the gateway to receive cross-profile Kanban task notifications by adding `notification_sources` to `~/.hermes/config.yaml`.\n-- `notification_sources: ['*']` accepts subscriptions from all profiles.\n-- `notification_sources: ['default', 'zilor-ppt']` or `\"default,zilor-ppt\"` restricts subscriptions to specified profiles.\n-- Omitting the key keeps the default behavior (profile isolation).\n-\n-## Do NOT\n-\n-- 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.\n-- 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.\n-- Modify files outside `$HERMES_KANBAN_WORKSPACE` unless the task body says to.\n-- Create follow-up tasks assigned to yourself — assign to the right specialist.\n-- Complete a task you didn't actually finish. Block it instead.\n-\n-## Pitfalls\n-\n-**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.\n-\n-**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.\n-\n-**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.\n-\n-## CLI fallback (for scripting)\n-\n-Every tool has a CLI equivalent for human operators and scripts:\n-- `kanban_show` ↔ `hermes kanban show <id> --json`\n-- `kanban_complete` ↔ `hermes kanban complete <id> --summary \"...\" --metadata '{...}'`\n-- `kanban_block` ↔ `hermes kanban block <id> \"reason\"`\n-- `kanban_create` ↔ `hermes kanban create \"title\" --assignee <profile> [--parent <id>]`\n-- etc.\n-\n-Use the tools from inside an agent; the CLI exists for the human at the terminal."]},{"file":"website/docs/user-guide/skills/optional/creative/creative-kanban-video-orchestrator.md","hunks":["@@ -21,7 +21,7 @@ Plan, set up, and monitor a multi-agent video production pipeline backed by Herm\n | License | MIT |\n | Platforms | linux, macos, windows |\n | Tags | `video`, `kanban`, `multi-agent`, `orchestration`, `production-pipeline` |\n-| 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) |\n+| 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) |\n \n ## Reference: full SKILL.md\n ","@@ -187,7 +187,7 @@ task graphs. See **[references/examples.md](https://github.com/NousResearch/herm\n    file` toolset, the director's `SOUL.md` rules forbid it from executing\n    work itself. It decomposes and routes only — every concrete task becomes\n    a `hermes kanban create` call to a specialist profile. The\n-   `kanban-orchestrator` skill spells this out further.\n+   auto-injected kanban orchestration guidance spells this out further.\n \n 7. **Don't over-decompose.** A 30-second product video does NOT need 20 tasks.\n    Aim for the smallest task graph that still parallelizes well and exposes the"]},{"file":"website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/skills-catalog.md","hunks":["@@ -62,8 +62,7 @@ Hermes 在执行 `hermes update` 时也会同步内置技能，但同步清单\n \n | 技能 | 描述 | 路径 |\n |-------|-------------|------|\n-| [`kanban-orchestrator`](/user-guide/skills/bundled/devops/devops-kanban-orchestrator) | 面向编排器（orchestrator）配置文件的分解策略与反诱惑规则，用于通过 Kanban 路由工作。\"不要自己做工作\"规则和基本生命周期会自动注入每个 Kanban worker 的系统 prompt；如需更深入的细节，请加载此技能。 | `devops/kanban-orchestrator` |\n-| [`kanban-worker`](/user-guide/skills/bundled/devops/devops-kanban-worker) | Hermes Kanban worker 的陷阱、示例和边界情况。生命周期本身会作为 `KANBAN_GUIDANCE` 自动注入每个 worker 的系统 prompt（来自 `agent/prompt_builder.py`）；当需要更深入细节时加载此技能。 | `devops/kanban-worker` |\n+\n \n ## dogfood\n "]},{"file":"website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/features/kanban-worker-lanes.md","hunks":["@@ -7,7 +7,7 @@\n - **运维人员**：选择将哪些通道接入看板（创建哪些 profile，使用哪些 assignee）。\n - **插件/集成作者**：希望添加新的通道形态（封装 Codex / Claude Code / OpenCode 的 CLI worker、容器化审查 worker、通过 API 拉取任务的非 Hermes 服务）。\n \n-如果你编写的是 worker 代码本身——即运行在通道*内部*的 agent——请参阅 [`kanban-worker`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-worker/SKILL.md) skill，其中包含更深入的操作细节。\n+如果你编写的是 worker 代码本身——即运行在通道*内部*的 agent——kanban 生命周期与参考细节会自动注入到 worker 的系统提示中（[`agent/prompt_builder.py`](https://github.com/NousResearch/hermes-agent/blob/main/agent/prompt_builder.py) 中的 `KANBAN_GUIDANCE` 块）。\n \n ## 层级结构\n ","@@ -64,7 +64,7 @@ kanban 内核强制要求每次运行恰好由其中一项终止。既未调用\n - **先将结构化元数据写入 `kanban_comment`**，因为 `kanban_block` 只携带人类可读的 `reason`。Comment 是持久的注解通道——所有与审计相关的字段（changed_files、tests_run、diff_path 或 PR url、决策记录）都应放在这里。\n - **Reviewer 批准并解除阻塞**，这将重新生成 worker 并附带 comment 线程用于后续跟进；或通过另一条 comment 要求修改，下一次 worker 运行时将通过 `kanban_show` 的上下文看到这些内容。\n \n-[`kanban-worker`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-worker/SKILL.md) skill 中有 `kanban_complete`（真正终态的任务——拼写修复、文档变更、研究报告）和 `review-required` block 模式的完整示例。\n+自动注入的 `KANBAN_GUIDANCE` 同时涵盖 `kanban_complete`（真正终态的任务——拼写修复、文档变更、研究报告）和 `review-required` block 模式。\n \n ## 日志与审计追踪\n ","@@ -80,9 +80,9 @@ kanban 内核强制要求每次运行恰好由其中一项终止。既未调用\n \n ### Hermes profile 通道（默认）\n \n-当前所有 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 外无需任何额外配置。\n+当前所有 kanban worker 采用的形态：assignee 是 profile 名称，调度器生成 `hermes -p <profile>`，worker 会自动获得注入的 `KANBAN_GUIDANCE` 系统提示块，并使用 `kanban_*` 工具终止运行。除定义 profile 外无需任何额外配置。\n \n-为你的 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）。\n+为你的 fleet 创建 profile 时，选择与你希望 orchestrator 路由到的*角色*相匹配的名称。orchestrator（如果存在）通过 `hermes profile list` 发现你的 profile 名称——系统不假设固定的名单（orchestrator 侧的契约也是注入的 `KANBAN_GUIDANCE` 的一部分）。\n \n ### Orchestrator profile 通道\n ","@@ -110,5 +110,4 @@ profile 通道的特化形态：orchestrator 是一个 Hermes profile，其工\n \n - [Kanban 概览](./kanban) — 面向用户的介绍。\n - [Kanban 教程](./kanban-tutorial) — 开启仪表板的完整演练。\n-- [`kanban-worker`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-worker/SKILL.md) — worker 进程加载的 skill。\n-- [`kanban-orchestrator`](https://github.com/NousResearch/hermes-agent/blob/main/skills/devops/kanban-orchestrator/SKILL.md) — orchestrator 侧。\n\\ No newline at end of file\n+- [`KANBAN_GUIDANCE`](https://github.com/NousResearch/hermes-agent/blob/main/agent/prompt_builder.py) — 注入到每个 kanban worker 系统提示中的 worker + orchestrator 生命周期。\n\\ No newline at end of file"]},{"file":"website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/features/kanban.md","hunks":["@@ -240,7 +240,7 @@ kanban_create(\n kanban_complete(summary=\"decomposed into 2 research tasks + 1 writer; linked dependencies\")\n ```\n \n-\"（编排器）\"工具 —— `kanban_list`、`kanban_create`、`kanban_link`、`kanban_unblock`，以及对外部任务的 `kanban_comment` —— 通过同一工具集提供；约定（由 `kanban-orchestrator` skill 强制执行）是 worker 配置文件不进行扇出或路由无关工作，编排器配置文件不执行实现工作。调度器启动的 worker 仍然针对破坏性生命周期操作限定在任务范围内，无法修改无关任务。\n+\"（编排器）\"工具 —— `kanban_list`、`kanban_create`、`kanban_link`、`kanban_unblock`，以及对外部任务的 `kanban_comment` —— 通过同一工具集提供；约定（编码在自动注入的 kanban 指引中）是 worker 配置文件不进行扇出或路由无关工作，编排器配置文件不执行实现工作。调度器启动的 worker 仍然针对破坏性生命周期操作限定在任务范围内，无法修改无关任务。\n \n ### 为什么使用工具而不是 shell 执行 `hermes kanban`\n ","@@ -252,7 +252,7 @@ kanban_complete(summary=\"decomposed into 2 research tasks + 1 writer; linked dep\n \n **对普通会话零 schema 占用。** 普通的 `hermes chat` 会话在其 schema 中没有任何 `kanban_*` 工具，除非活动配置文件为编排器工作显式启用了 `kanban` 工具集。调度器启动的任务 worker 因为设置了 `HERMES_KANBAN_TASK` 而获得任务范围的工具；编排器配置文件通过配置获得更广泛的路由界面。对于从不使用 kanban 的用户，没有工具膨胀。\n \n-`kanban-worker` 和 `kanban-orchestrator` skill 教导模型何时调用哪个工具以及调用顺序。\n+自动注入的 kanban 指引教导模型何时调用哪个工具以及调用顺序。\n \n ### 推荐的交接证据\n ","@@ -280,9 +280,9 @@ kanban_complete(summary=\"decomposed into 2 research tasks + 1 writer; linked dep\n \n 不要将密钥、原始日志、token（令牌）、OAuth 材料和无关记录放入 `metadata`。改为存储指针和摘要。如果任务没有文件或测试，在 `summary` 中明确说明，并在 `metadata` 中放置确实存在的证据，例如来源 URL、issue id 或手动审查步骤。\n \n-### Worker skill\n+### Worker 生命周期\n \n-任何应该能够处理 kanban 任务的配置文件都必须加载 `kanban-worker` skill。它通过**工具调用**（而非 CLI 命令）教导 worker 完整的生命周期：\n+任何处理 kanban 任务的配置文件都会**自动**获得 worker 生命周期 —— 它在启动时被注入到 worker 的系统 prompt 中（`KANBAN_GUIDANCE` 块），因此**无需安装或配置任何东西**。它通过**工具调用**（而非 CLI 命令）教导 worker 完整的生命周期：\n \n 1. 启动时，调用 `kanban_show()` 读取标题 + 正文 + 父级交接 + 先前尝试 + 完整评论线程。\n 2. 通过终端工具执行 `cd $HERMES_KANBAN_WORKSPACE`，在那里完成工作。","@@ -291,20 +291,6 @@ kanban_complete(summary=\"decomposed into 2 research tasks + 1 writer; linked dep\n \n 最终的 `kanban_complete` / `kanban_block` 调用是 worker 协议的一部分。如果 worker 进程以状态 0 退出而任务仍处于 `running` 状态，调度器将其视为协议违规，发出 `protocol_violation` 事件，并在下一个 tick 自动阻塞任务而不是重新启动它进入同一循环。这通常意味着模型写了一个纯文本答案并退出，而没有使用 Kanban 工具界面。\n \n-`kanban-worker` 是一个内置 skill，在安装和更新期间同步到每个配置文件 —— 无需单独的 Skills Hub 安装步骤。验证它是否存在于你用于 kanban worker 的配置文件中（`researcher`、`writer`、`ops` 等）：\n-\n-```bash\n-hermes -p <your-worker-profile> skills list | grep kanban-worker\n-```\n-\n-如果内置副本丢失，为该配置文件恢复它：\n-\n-```bash\n-hermes -p <your-worker-profile> skills reset kanban-worker --restore\n-```\n-\n-调度器在启动每个 worker 时也会自动传递 `--skills kanban-worker`，因此即使配置文件的默认 skills 配置不包含它，worker 也始终拥有该模式库。\n-\n ### 为特定任务固定额外 skill\n \n 有时单个任务需要受让人配置文件默认不携带的专业上下文 —— 需要 `translation` skill 的翻译任务、需要 `github-code-review` 的审查任务、需要 `security-pr-audit` 的安全审计。与其每次都编辑受让人的配置文件，不如直接将 skill 附加到任务上。","@@ -340,11 +326,11 @@ hermes kanban create \"audit auth flow\" \\\n \n **从仪表盘**，在内联创建表单的 **skills** 字段中以逗号分隔输入 skill 名称。\n \n-这些 skill 是对内置 `kanban-worker` 的**补充** —— 调度器为每个 skill（以及内置的）发出一个 `--skills <name>` 标志，因此 worker 启动时加载了所有这些 skill。skill 名称必须与受让人配置文件上实际安装的 skill 匹配（运行 `hermes skills list` 查看可用内容）；没有运行时安装。\n+调度器为列出的每个 skill 发出一个 `--skills <name>` 标志，因此 worker 在自动注入的 kanban 指引之上加载了所有这些 skill。skill 名称必须与受让人配置文件上实际安装的 skill 匹配（运行 `hermes skills list` 查看可用内容）；没有运行时安装。\n \n-### 编排器 skill\n+### 编排器的行为方式\n \n-**行为良好的编排器不会自己做工作。** 它将用户的目标分解为任务，链接它们，将每个任务分配给你设置的配置文件之一，然后退后。`kanban-orchestrator` skill 将此编码为工具调用模式：反诱惑规则、Step-0 配置文件发现提示（调度器在未知受让人名称上静默失败，因此编排器必须将每张卡片落地到你机器上实际存在的配置文件），以及以 `kanban_create` / `kanban_link` / `kanban_comment` 为核心的分解手册。\n+**行为良好的编排器不会自己做工作。** 它将用户的目标分解为任务，链接它们，将每个任务分配给你设置的配置文件之一，然后退后。编排器指引 —— 反诱惑规则、Step-0 配置文件发现提示（调度器在未知受让人名称上静默失败，因此编排器必须将每张卡片落地到你机器上实际存在的配置文件），以及以 `kanban_create` / `kanban_link` / `kanban_comment` 为核心的分解手册 —— 会自动注入到 worker 的系统 prompt 中；无需安装任何东西。\n \n 典型的编排器轮次（两个并行研究员交接给一个写作者）：\n ","@@ -365,17 +351,7 @@ kanban_complete(\n )\n ```\n \n-`kanban-orchestrator` 是一个内置 skill。它在安装和更新期间同步到每个配置文件，因此无需单独的 Skills Hub 安装步骤。验证它是否存在于你的编排器配置文件中：\n-\n-```bash\n-hermes -p orchestrator skills list | grep kanban-orchestrator\n-```\n-\n-如果内置副本丢失，为该配置文件恢复它：\n-\n-```bash\n-hermes -p orchestrator skills reset kanban-orchestrator --restore\n-```\n+编排器指引随 worker 的系统 prompt 自动提供 —— 无需按配置文件安装或同步任何东西。\n \n 为获得最佳效果，将其与工具集限制为看板操作（`kanban`、`gateway`、`memory`）的配置文件配对，这样编排器即使尝试也无法执行实现任务。\n "]},{"file":"/dev/null","hunks":["@@ -1,207 +0,0 @@\n----\n-title: \"Kanban Orchestrator\"\n-sidebar_label: \"Kanban Orchestrator\"\n-description: \"用于通过 Kanban 路由工作的编排器 profile 的任务分解手册及反诱惑规则\"\n----\n-\n-{/* 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. */}\n-\n-# Kanban Orchestrator\n-\n-用于通过 Kanban 路由工作的编排器 profile 的任务分解手册及反诱惑规则。\"不要自己执行工作\"规则和基本生命周期会自动注入每个 kanban worker 的系统 prompt（提示词）中；本 skill 是当你专门扮演编排器角色时使用的更深层手册。\n-\n-## Skill 元数据\n-\n-| | |\n-|---|---|\n-| 来源 | 内置（默认安装） |\n-| 路径 | `skills/devops/kanban-orchestrator` |\n-| 版本 | `3.0.0` |\n-| 平台 | linux, macos, windows |\n-| 标签 | `kanban`, `multi-agent`, `orchestration`, `routing` |\n-| 相关 skill | [`kanban-worker`](/user-guide/skills/bundled/devops/devops-kanban-worker) |\n-\n-## 参考：完整 SKILL.md\n-\n-:::info\n-以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。\n-:::\n-\n-# Kanban Orchestrator — 任务分解手册\n-\n-> **核心 worker 生命周期**（包括 `kanban_create` 扇出模式和\"分解而非执行\"规则）通过 `KANBAN_GUIDANCE` 系统 prompt 块自动注入每个 kanban 进程。本 skill 是当你作为编排器 profile、整个职责就是路由时使用的更深层手册。\n-\n-## Profile 由用户配置——不是固定名单\n-\n-Hermes 的配置因人而异。有些用户运行单个 profile 处理所有事务；有些运行小型集群（`docker-worker`、`cron-worker`）；有些运行自己命名的精选专家团队。**没有默认的专家名单**——编排器 skill 不知道此机器上存在哪些 profile。\n-\n-在扇出之前，你必须基于实际存在的 profile 来制定分解方案。调度器会静默地忽略无法识别的 assignee 名称——它不会自动纠正、不会建议、也不会回退。因此，在只有 `docker-worker` 的配置上，分配给 `researcher` 的卡片会永远停留在 `ready` 状态。\n-\n-**第 0 步：在规划前发现可用的 profile。**\n-\n-使用以下方法之一：\n-\n-- `hermes profile list` — 打印此机器上已配置的 profile 表。如果有终端工具，通过终端工具运行；否则询问用户。\n-- `kanban_list(assignee=\"<some-name>\")` — 验证单个名称。对于未知 assignee 返回空列表（而非报错），因此只能确认你已在考虑的名称。\n-- **直接询问用户。** 当目标需要多个专家时，\"你配置了哪些 profile？\"是一个合理的开场问题。\n-\n-将结果缓存在工作记忆中供本次对话使用。每轮都重新询问会浪费工具调用。\n-\n-## 何时使用看板（vs. 直接执行工作）\n-\n-当以下任一条件成立时，创建 Kanban 任务：\n-\n-1. **需要多个专家。** 研究 + 分析 + 写作需要三个 profile。\n-2. **工作应在崩溃或重启后继续存在。** 长期运行、周期性或重要的任务。\n-3. **用户可能需要介入。** 任意步骤需要人工参与。\n-4. **多个子任务可以并行运行。** 扇出以提高速度。\n-5. **预期需要审查/迭代。** 审查者 profile 循环处理起草者的输出。\n-6. **审计追踪很重要。** 看板行永久保存在 SQLite 中。\n-\n-如果*以上均不适用*——这是一个小型一次性推理任务——改用 `delegate_task` 或直接回答用户。\n-\n-## 反诱惑规则\n-\n-你的职责描述是\"路由，不执行\"。执行该规则的约束：\n-\n-- **不要自己执行工作。** 你受限的工具集通常甚至不包含用于实现的终端/文件/代码/网络工具。如果你发现自己在\"快速修复这个\"——停下来，为合适的专家创建任务。\n-- **对于任何具体任务，创建 Kanban 任务并分配它。** 每一次都如此。\n-- **在创建卡片之前拆分多通道请求。** 用户的一个 prompt 可能包含多个独立的工作流。先提取这些通道，然后每个通道创建一张卡片，而不是将不相关的工作打包到单个实现者卡片中。\n-- **并行运行独立通道。** 如果两张卡片不需要彼此的输出，不要链接它们，让调度器可以扇出处理。只链接真正的数据依赖。\n-- **永远不要将依赖工作创建为独立的 ready 卡片。** 如果一张卡片必须等待另一张卡片，在原始 `kanban_create` 调用中传入 `parents=[...]`。不要先创建再链接，也不要依赖卡片正文中的\"等待 T1\"之类的描述。\n-- **如果没有专家适合现有 profile，询问用户应创建哪个 profile 或使用哪个现有 profile。** 不要凭空发明 profile 名称；调度器会静默丢弃未知 assignee。\n-- **分解、路由、汇总——这就是全部工作。**\n-\n-## 任务分解手册\n-\n-### 第 1 步——理解目标\n-\n-如果目标不明确，提出澄清性问题。询问的成本很低；派出错误的团队代价高昂。\n-\n-### 第 2 步——草拟任务图\n-\n-在创建任何内容之前，在回复用户时大声（在响应中）草拟任务图。将每个具体工作流视为候选卡片：\n-\n-1. 从请求中提取通道。\n-2. 将每个通道映射到第 0 步中发现的某个 profile。如果某个通道不适合任何现有 profile，询问用户使用或创建哪个。\n-3. 决定每个通道是独立的还是受另一个通道门控的。\n-4. 将独立通道创建为无父链接的并行卡片。\n-5. 将综合/审查/集成卡片创建时带上其所依赖通道的父链接。使用未完成父任务创建的子任务从 `todo` 开始；调度器仅在每个父任务完成后才将其提升为 `ready`。\n-\n-应该扇出的 prompt 示例（使用占位符 profile 名称——替换为用户配置中实际存在的名称）：\n-\n-- \"构建一个应用\" → 一张卡片给面向设计的 profile 负责产品/UI 方向，一两张卡片给工程 profile 负责实现，如果用户有审查者 profile，再加一张后续的集成/审查卡片。\n-- \"修复阻塞项并检查模型变体\" → 一张实现卡片用于修复阻塞项，加一张发现/研究卡片用于配置/源码验证。最终的审查者卡片可以依赖两者。\n-- \"研究文档并实现\" → 文档研究卡片可以与代码库发现卡片并行运行；只有当实现真正需要这些发现时才等待。\n-- \"分析这张截图并找到相关代码\" → 一张卡片给具备视觉能力的 profile 进行视觉分析，同时另一张卡片搜索代码库。\n-\n-\"也\"、\"最后\"或\"和\"等词语不自动意味着依赖关系。它们通常意味着\"确保在汇报前涵盖这一点\"。只有当一张卡片在另一张卡片的输出存在之前无法开始时，才链接任务。\n-\n-在创建卡片之前将任务图展示给用户。让他们纠正——包括哪个实际 profile 名称应该负责每个通道。\n-\n-### 第 3 步——创建任务并链接\n-\n-使用第 0 步中的 profile 名称。以下示例使用占位符 `<profile-A>`、`<profile-B>`、`<profile-C>`——替换为用户实际拥有的名称。\n-\n-```python\n-t1 = kanban_create(\n-    title=\"research: Postgres cost vs current\",\n-    assignee=\"<profile-A>\",  # whichever profile handles research on this setup\n-    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.\",\n-    tenant=os.environ.get(\"HERMES_TENANT\"),\n-)[\"task_id\"]\n-\n-t2 = kanban_create(\n-    title=\"research: Postgres performance vs current\",\n-    assignee=\"<profile-A>\",  # same profile, run in parallel\n-    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.\",\n-)[\"task_id\"]\n-\n-t3 = kanban_create(\n-    title=\"synthesize migration recommendation\",\n-    assignee=\"<profile-B>\",  # whichever profile does synthesis/analysis\n-    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.\",\n-    parents=[t1, t2],\n-)[\"task_id\"]\n-\n-t4 = kanban_create(\n-    title=\"draft decision memo\",\n-    assignee=\"<profile-C>\",  # whichever profile drafts user-facing prose\n-    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.\",\n-    parents=[t3],\n-)[\"task_id\"]\n-```\n-\n-`parents=[...]` 门控提升——子任务保持在 `todo` 状态，直到每个父任务达到 `done`，然后自动提升为 `ready`。无需手动协调；调度器和依赖引擎会处理这一切。\n-\n-如果任务图有依赖关系，先创建父卡片，捕获其返回的 id，并在子卡片的 `kanban_create` 调用中将这些 id 包含在 `parents` 列表中。避免并行创建所有卡片后再链接；这会产生一个时间窗口，调度器可能在子任务的输入存在之前就认领它。\n-\n-### 第 4 步——完成你自己的任务\n-\n-如果你是作为任务被派生的（例如，规划者 profile 被分配了 `T0: \"调查 Postgres 迁移\"`），用你创建内容的摘要标记它为完成：\n-\n-```python\n-kanban_complete(\n-    summary=\"decomposed into T1-T4: 2 research lanes in parallel, 1 synthesis on their outputs, 1 prose draft on the recommendation\",\n-    metadata={\n-        \"task_graph\": {\n-            \"T1\": {\"assignee\": \"<profile-A>\", \"parents\": []},\n-            \"T2\": {\"assignee\": \"<profile-A>\", \"parents\": []},\n-            \"T3\": {\"assignee\": \"<profile-B>\", \"parents\": [\"T1\", \"T2\"]},\n-            \"T4\": {\"assignee\": \"<profile-C>\", \"parents\": [\"T3\"]},\n-        },\n-    },\n-)\n-```\n-\n-### 第 5 步——向用户汇报\n-\n-用简明的文字告诉他们你创建了什么，并说明你使用的实际 profile 名称：\n-\n-> 我已排队 4 个任务：\n-> - **T1**（`<profile-A>`）：成本对比\n-> - **T2**（`<profile-A>`）：性能对比，与 T1 并行\n-> - **T3**（`<profile-B>`）：综合 T1 + T2 生成建议\n-> - **T4**（`<profile-C>`）：将 T3 转化为 CTO 备忘录\n->\n-> 调度器现在将认领 T1 和 T2。T3 在两者完成后启动。T4 完成时你会收到 gateway 通知。使用仪表板或 `hermes kanban tail <id>` 跟踪进度。\n-\n-## 常见模式\n-\n-**扇出 + 扇入（研究 → 综合）：** N 张无父链接的研究类卡片，一张以所有研究卡片为父的综合卡片。\n-\n-**并行实现 + 验证：** 一张实现者卡片进行变更，同时一张探索/研究卡片验证配置、文档或源码映射。审查者卡片可以依赖两者。不要因为用户在一句话中同时提到了两者，就让实现者承担不相关的验证工作。\n-\n-**带门控的流水线：** `planner → implementer → reviewer`。每个阶段的 `parents=[previous_task]`。审查者阻塞或完成；如果审查者阻塞，操作员带着反馈解除阻塞并重新派发。\n-\n-**同 profile 队列：** N 个任务，全部分配给同一个 profile，彼此之间无依赖。调度器串行处理——该 profile 按优先级顺序处理它们，在自己的记忆中积累经验。\n-\n-**人工参与循环：** 任何任务都可以调用 `kanban_block()` 等待输入。调度器在 `/unblock` 后重新派发。评论线程携带完整上下文。\n-\n-## 常见陷阱\n-\n-**发明不存在的 profile 名称。** 调度器会静默地忽略无法识别的 assignee——卡片会永远停留在 `ready` 状态。始终从第 0 步发现的 profile 中分配；如果不确定，询问用户。\n-\n-**将独立通道打包到一张卡片中。** 如果用户要求两个独立的结果，创建两张卡片。示例：\"修复阻塞项并检查模型变体\"不是一个修复任务；为修复创建一张修复/工程卡片，为变体检查创建一张探索/研究卡片，然后可选地将审查门控在两者之上。\n-\n-**因措辞而过度链接。** \"最后检查 X\"如果 X 是静态配置、文档或源码发现，仍然可以与实现并行。只有当检查依赖于实现结果时，才将其链接在实现之后。\n-\n-**忘记依赖链接。** 如果任务图说 `research -> implement -> review`，不要将所有任务创建为独立的 ready 卡片。使用父链接，确保 implement/review 在其输入存在之前无法运行。\n-\n-**重新分配 vs. 新任务。** 如果审查者以\"需要修改\"阻塞，创建一个从审查者任务链接的**新**任务——不要用严厉的眼神重新运行同一个任务。新任务分配给原始实现者 profile。\n-\n-**链接的参数顺序。** `kanban_link(parent_id=..., child_id=...)` — 父任务在前。混淆顺序会将错误的任务降级为 `todo`。\n-\n-**如果形状取决于中间发现，不要预先创建整个任务图。** 如果 T3 的结构取决于 T1 和 T2 的发现，让 T3 作为一个\"综合发现\"任务存在，其第一步是读取父任务的交接内容并规划其余部分。编排器可以派生编排器。\n-\n-**Tenant 继承。** 如果你的环境中设置了 `HERMES_TENANT`，在每次 `kanban_create` 调用中传入 `tenant=os.environ.get(\"HERMES_TENANT\")`，以确保子任务保持在同一命名空间中。\n-\n-## 恢复卡住的 worker\n-\n-当一个 worker profile 持续崩溃、产生幻觉或被自身错误阻塞时（通常是：错误的模型、缺少 skill、凭据损坏），kanban 仪表板会在任务上标记 ⚠ 徽章，并在抽屉中打开**恢复**部分。三个主要操作：\n-\n-1. **Reclaim**（或 `hermes kanban reclaim <task_id>`）——立即中止正在运行的 worker 并将任务重置为 `ready`。现有认领 TTL 约为 15 分钟；这是最快的解决路径。\n-2. **Reassign**（或 `hermes kanban reassign <task_id> <new-profile> --reclaim`）——将任务切换到不同的 profile（此配置上存在的 profile）并让调度器用新 worker 认领它。\n-3. **更改 profile 模型**——仪表板会打印 `hermes -p <profile> model` 的复制粘贴提示，因为 profile 配置存储在磁盘上；在终端中编辑它，然后 Reclaim 以使用新模型重试。\n-\n-当 worker 的 `kanban_complete(created_cards=[...])` 声明包含不存在或非该 worker profile 创建的卡片 id 时（门控会阻止完成），或者自由格式摘要引用了无法解析的 `t_<hex>` id 时（建议性文本扫描，非阻塞），会出现幻觉警告。两者都会产生审计事件，即使在恢复操作后也会持久保存——追踪记录保留用于调试。\n\\ No newline at end of file"]},{"file":"/dev/null","hunks":["@@ -1,202 +0,0 @@\n----\n-title: \"Kanban Worker — Hermes Kanban worker 的陷阱、示例与边界情况\"\n-sidebar_label: \"Kanban Worker\"\n-description: \"Hermes Kanban worker 的陷阱、示例与边界情况\"\n----\n-\n-{/* 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. */}\n-\n-# Kanban Worker\n-\n-Hermes Kanban worker 的陷阱、示例与边界情况。生命周期本身会自动注入到每个 worker 的系统 prompt（提示词）中，作为 `KANBAN_GUIDANCE`（来自 `agent/prompt_builder.py`）；当你需要深入了解特定场景时，加载此 skill 即可。\n-\n-## Skill 元数据\n-\n-| | |\n-|---|---|\n-| 来源 | 内置（默认安装） |\n-| 路径 | `skills/devops/kanban-worker` |\n-| 版本 | `2.0.0` |\n-| 平台 | linux, macos, windows |\n-| 标签 | `kanban`, `multi-agent`, `collaboration`, `workflow`, `pitfalls` |\n-| 相关 skill | [`kanban-orchestrator`](/user-guide/skills/bundled/devops/devops-kanban-orchestrator) |\n-\n-## 参考：完整 SKILL.md\n-\n-:::info\n-以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。\n-:::\n-\n-# Kanban Worker — 陷阱与示例\n-\n-> 你看到此 skill，是因为 Hermes Kanban 调度器以 `--skills kanban-worker` 参数将你作为 worker 派生——它会为每个被派发的 worker 自动加载。**生命周期**（6 个步骤：orient → work → heartbeat → block/complete）也存在于自动注入到你系统 prompt 中的 `KANBAN_GUIDANCE` 块里。此 skill 是更深层的细节：良好的交接形式、重试诊断、边界情况。\n-\n-## 工作区处理\n-\n-你的工作区类型决定了你在 `$HERMES_KANBAN_WORKSPACE` 内部的行为方式：\n-\n-| 类型 | 含义 | 操作方式 |\n-|---|---|---|\n-| `scratch` | 全新的临时目录，仅供你使用 | 自由读写；任务归档后会被 GC 回收。 |\n-| `dir:<path>` | 共享的持久化目录 | 其他运行实例会读取你写入的内容。将其视为长期状态。路径保证为绝对路径（内核拒绝相对路径）。 |\n-| `worktree` | 位于已解析路径的 Git worktree | 若 `.git` 不存在，先从主仓库执行 `git worktree add <path> <branch>`，然后 cd 进去正常工作。在此提交工作。 |\n-\n-## 租户隔离\n-\n-若 `$HERMES_TENANT` 已设置，则该任务属于某个租户命名空间。在读写持久化内存时，请为内存条目添加租户前缀，以防上下文跨租户泄漏：\n-\n-- 正确：`business-a: Acme is our biggest customer`\n-- 错误（会泄漏）：`Acme is our biggest customer`\n-\n-## 良好的 summary + metadata 形式\n-\n-`kanban_complete(summary=..., metadata=...)` 的交接方式是下游 worker 读取你工作成果的途径。以下是有效的模式：\n-\n-**编码任务：**\n-```python\n-kanban_complete(\n-    summary=\"shipped rate limiter — token bucket, keys on user_id with IP fallback, 14 tests pass\",\n-    metadata={\n-        \"changed_files\": [\"rate_limiter.py\", \"tests/test_rate_limiter.py\"],\n-        \"tests_run\": 14,\n-        \"tests_passed\": 14,\n-        \"decisions\": [\"user_id primary, IP fallback for unauthenticated requests\"],\n-    },\n-)\n-```\n-\n-**需要人工审查的编码任务（review-required）：**\n-\n-对于大多数涉及代码变更的任务，在人工审查者过目之前，工作并未真正*完成*。应使用 block 而非 complete，并在 `reason` 前加 `review-required: ` 前缀，以便仪表板将该行标记为待审查。先将结构化元数据（变更文件、测试计数、diff/PR url）写入 comment，因为 `kanban_block` 只携带人类可读的原因——comment 是持久化注释的渠道。审查者可执行 `hermes kanban unblock <id>` 批准（这会携带 comment 线程重新派生你以处理后续事项），或通过另一条 comment 要求修改。\n-\n-```python\n-import json\n-\n-kanban_comment(\n-    body=\"review-required handoff:\\n\" + json.dumps({\n-        \"changed_files\": [\"rate_limiter.py\", \"tests/test_rate_limiter.py\"],\n-        \"tests_run\": 14,\n-        \"tests_passed\": 14,\n-        \"diff_path\": \"/path/to/worktree\",  # or PR url if pushed\n-        \"decisions\": [\"user_id primary, IP fallback for unauthenticated requests\"],\n-    }, indent=2),\n-)\n-kanban_block(\n-    reason=\"review-required: rate limiter shipped, 14/14 tests pass — needs eyes on the user_id/IP fallback choice before merging\",\n-)\n-```\n-\n-仅在任务真正终结时使用 `kanban_complete`——例如单行拼写修复、无功能影响的文档变更，或产出物本身即为成果的研究任务。\n-\n-**研究任务：**\n-```python\n-kanban_complete(\n-    summary=\"3 competing libraries reviewed; vLLM wins on throughput, SGLang on latency, Tensorrt-LLM on memory efficiency\",\n-    metadata={\n-        \"sources_read\": 12,\n-        \"recommendation\": \"vLLM\",\n-        \"benchmarks\": {\"vllm\": 1.0, \"sglang\": 0.87, \"trtllm\": 0.72},\n-    },\n-)\n-```\n-\n-**审查任务：**\n-```python\n-kanban_complete(\n-    summary=\"reviewed PR #123; 2 blocking issues found (SQL injection in /search, missing CSRF on /settings)\",\n-    metadata={\n-        \"pr_number\": 123,\n-        \"findings\": [\n-            {\"severity\": \"critical\", \"file\": \"api/search.py\", \"line\": 42, \"issue\": \"raw SQL concat\"},\n-            {\"severity\": \"high\", \"file\": \"api/settings.py\", \"issue\": \"missing CSRF middleware\"},\n-        ],\n-        \"approved\": False,\n-    },\n-)\n-```\n-\n-请将 `metadata` 的结构设计为下游解析器（审查者、聚合器、调度器）无需重新阅读你的文字描述即可直接使用。\n-\n-## 认领你实际创建的卡片\n-\n-若你的运行产生了新的 kanban 任务（通过 `kanban_create`），请在 `kanban_complete` 的 `created_cards` 中传入这些 id。内核会验证每个 id 是否存在且由你的 profile 创建；任何幻构的 id 都会导致完成操作被阻断，并附带错误列表说明问题所在，且被拒绝的尝试会永久记录在任务的事件日志中。**只列出你从成功的 `kanban_create` 返回值中捕获的 id——绝不凭空捏造 id，绝不粘贴来自早期运行的 id，绝不认领其他 worker 创建的卡片。**\n-\n-```python\n-# 正确 — 捕获返回值，然后认领。\n-c1 = kanban_create(title=\"remediate SQL injection\", assignee=\"security-worker\")\n-c2 = kanban_create(title=\"fix CSRF middleware\", assignee=\"web-worker\")\n-\n-kanban_complete(\n-    summary=\"Review done; spawned remediations for both findings.\",\n-    metadata={\"pr_number\": 123, \"approved\": False},\n-    created_cards=[c1[\"task_id\"], c2[\"task_id\"]],\n-)\n-```\n-\n-```python\n-# 错误 — 认领没有捕获返回值的 id。\n-kanban_complete(\n-    summary=\"Created remediation cards t_a1b2c3d4, t_deadbeef\",  # 幻构\n-    created_cards=[\"t_a1b2c3d4\", \"t_deadbeef\"],                   # → 门控拒绝\n-)\n-```\n-\n-若 `kanban_create` 调用失败（异常、tool_error），则卡片未被创建——不要为其包含幻构 id。重试创建，或省略该 id 并在 summary 中说明失败情况。散文扫描阶段也会捕获你自由格式 summary 中无法解析的 `t_<hex>` 引用；这些不会阻断完成操作，但会在仪表板的任务上显示为建议性警告。\n-\n-## 能快速得到回应的 block 原因\n-\n-差：`\"stuck\"` — 人类没有任何上下文。\n-\n-好：一句话说明你需要的具体决策。将更长的上下文作为 comment 留下。\n-\n-```python\n-kanban_comment(\n-    task_id=os.environ[\"HERMES_KANBAN_TASK\"],\n-    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.\",\n-)\n-kanban_block(reason=\"Rate limit key choice: IP (simple, NAT-unsafe) or user_id (requires auth, skips anonymous endpoints)?\")\n-```\n-\n-block 消息是仪表板/gateway 通知器中显示的内容。comment 是人类打开任务时阅读的深层上下文。\n-\n-## 值得发送的 heartbeat\n-\n-好的 heartbeat 应说明进度：`\"epoch 12/50, loss 0.31\"`、`\"scanned 1.2M/2.4M rows\"`、`\"uploaded 47/120 videos\"`。\n-\n-差的 heartbeat：`\"still working\"`、空 notes、亚秒级间隔。最多每隔几分钟发送一次；对于约 2 分钟以内的任务可完全跳过。\n-\n-## 重试场景\n-\n-若你打开任务后 `kanban_show` 返回的 `runs: [...]` 中包含一个或多个已关闭的运行，说明你是一次重试。先前运行的 `outcome` / `summary` / `error` 会告诉你哪里出了问题。不要重复那条路径。典型的重试诊断：\n-\n-- `outcome: \"timed_out\"` — 上次尝试达到了 `max_runtime_seconds`。你可能需要将工作分块或缩短。\n-- `outcome: \"crashed\"` — OOM 或段错误。减少内存占用。\n-- `outcome: \"spawn_failed\"` + `error: \"...\"` — 通常是 profile 配置问题（缺少凭证、错误的 PATH）。通过 `kanban_block` 询问人类，而不是盲目重试。\n-- `outcome: \"reclaimed\"` + `summary: \"task archived...\"` — 操作员在上次运行期间将任务归档；你可能根本不应该在运行，请仔细检查状态。\n-- `outcome: \"blocked\"` — 上次尝试被阻断；解除阻断的 comment 现在应该已在线程中。\n-\n-## 禁止事项\n-\n-- 不要用 `delegate_task` 替代 `kanban_create`。`delegate_task` 用于你的运行内部的短期推理子任务；`kanban_create` 用于跨 agent 的、超出单次 API 循环的交接。\n-- 不要修改 `$HERMES_KANBAN_WORKSPACE` 之外的文件，除非任务正文明确要求。\n-- 不要创建分配给自己的后续任务——分配给合适的专家。\n-- 不要完成一个你实际上没有完成的任务。改为 block 它。\n-\n-## 陷阱\n-\n-**任务状态可能在调度与启动之间发生变化。** 从调度器认领任务到你的进程实际启动之间，任务可能已被 block、重新分配或归档。始终先执行 `kanban_show`。若其报告 `blocked` 或 `archived`，请停止——你不应该在运行。\n-\n-**工作区可能存在过期产物。** 尤其是 `dir:` 和 `worktree` 工作区可能包含来自先前运行的文件。阅读 comment 线程——它通常会解释你为何再次运行以及工作区处于何种状态。\n-\n-**当指导已可用时，不要依赖 CLI。** `kanban_*` 工具可在所有终端后端（Docker、Modal、SSH）上工作。从你的终端工具执行 `hermes kanban <verb>` 在容器化后端中会失败，因为 CLI 未安装在那里。如有疑问，使用工具。\n-\n-## CLI 回退（用于脚本）\n-\n-每个工具都有对应的 CLI 等价命令，供人工操作员和脚本使用：\n-- `kanban_show` ↔ `hermes kanban show <id> --json`\n-- `kanban_complete` ↔ `hermes kanban complete <id> --summary \"...\" --metadata '{...}'`\n-- `kanban_block` ↔ `hermes kanban block <id> \"reason\"`\n-- `kanban_create` ↔ `hermes kanban create \"title\" --assignee <profile> [--parent <id>]`\n-- 等等。\n-\n-在 agent 内部使用工具；CLI 供终端前的人类使用。\n\\ No newline at end of file"]},{"file":"website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/skills/optional/creative/creative-kanban-video-orchestrator.md","hunks":["@@ -21,7 +21,7 @@ description: \"规划、搭建并监控由 Hermes Kanban 支撑的多智能体视\n | 许可证 | MIT |\n | 平台 | linux, macos, windows |\n | 标签 | `video`, `kanban`, `multi-agent`, `orchestration`, `production-pipeline` |\n-| 相关技能 | [`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) |\n+| 相关技能 | [`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) |\n \n ## 参考：完整 SKILL.md\n ","@@ -146,7 +146,7 @@ director profile 从此接管，通过 kanban 工具集将工作分解并路由\n \n 5. **尊重现有技能。** 当某个场景适合现有技能时，相关渲染器应通过任务上的 `--skill <name>` 或 profile 中的 `always_load` 加载该技能。不要重新推导技能已提供的内容。\n \n-6. **director 绝不执行。** 即使拥有完整的 `kanban + terminal + file` 工具集，director 的 `SOUL.md` 规则也禁止其自行执行工作。它只负责分解和路由——每个具体任务都变成对专业 profile 的 `hermes kanban create` 调用。`kanban-orchestrator` 技能对此有进一步说明。\n+6. **director 绝不执行。** 即使拥有完整的 `kanban + terminal + file` 工具集，director 的 `SOUL.md` 规则也禁止其自行执行工作。它只负责分解和路由——每个具体任务都变成对专业 profile 的 `hermes kanban create` 调用。自动注入的 kanban 编排指引对此有进一步说明。\n \n 7. **不要过度分解。** 一个 30 秒的产品视频**不需要** 20 个任务。目标是最小任务图，同时仍能良好并行化并暴露正确的人工审核节点。\n "]},{"file":"website/sidebars.ts","hunks":["@@ -188,16 +188,6 @@ const sidebars: SidebarsConfig = {\n                     'user-guide/skills/bundled/data-science/data-science-jupyter-live-kernel',\n                   ],\n                 },\n-                {\n-                  type: 'category',\n-                  label: 'devops',\n-                  key: 'skills-bundled-devops',\n-                  collapsed: true,\n-                  items: [\n-                    'user-guide/skills/bundled/devops/devops-kanban-orchestrator',\n-                    'user-guide/skills/bundled/devops/devops-kanban-worker',\n-                  ],\n-                },\n                 {\n                   type: 'category',\n                   label: 'dogfood',\n"]}]},{"kind":"pr","number":54100,"title":"fix(kanban): warn and continue when optional skill is unavailable (#54088)","url":null,"state":"open","close_reason":{"category":"uncategorized","implication":"needs_llm"},"merged":false},{"kind":"pr","number":55585,"title":"fix(kanban): unknown skill warns instead of crashing the worker","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["cli.py","scripts/release.py","tui_gateway/server.py"],"fix_hunks":[{"file":"cli.py","hunks":["@@ -15359,7 +15359,21 @@ def main(\n         )\n         if missing_skills:\n             missing_display = \", \".join(missing_skills)\n-            raise ValueError(f\"Unknown skill(s): {missing_display}\")\n+            # If at least one skill loaded, degrade gracefully: skip the\n+            # unknown ones and continue. A typo'd skill name should not crash\n+            # the worker (which auto-blocks the Kanban task after retries).\n+            # Only when EVERY requested skill is missing do we hard-fail, so a\n+            # fully-misconfigured worker fails loudly instead of running blind.\n+            if loaded_skills:\n+                logger.warning(\n+                    \"Unknown skill(s) requested, skipping: %s. \"\n+                    \"Continuing with: %s. \"\n+                    \"List available skills with `hermes skills list`.\",\n+                    missing_display,\n+                    \", \".join(loaded_skills),\n+                )\n+            else:\n+                raise ValueError(f\"Unknown skill(s): {missing_display}\")\n         if skills_prompt:\n             cli.system_prompt = \"\\n\\n\".join(\n                 part for part in (cli.system_prompt, skills_prompt) if part"]},{"file":"scripts/release.py","hunks":["@@ -45,6 +45,7 @@\n \n # Auto-extracted from noreply emails + manual overrides\n AUTHOR_MAP = {\n+    \"[redacted:email]\": \"jimmyjohansson84\",  # PR #27123 salvage (Kanban unknown-skill warn-instead-of-crash; #27136)\n     \"[redacted:email]\": \"theAgenticBuilder\",  # PR #14180 salvage (route delegate_task progress lines through _safe_print so ACP stdio JSON-RPC frames stay clean)\n     \"[redacted:email]\": \"huangxudong663-sys\",  # PR #15157 salvage (isinstance(dict) guard on tool-call model_extra; NVIDIA NIM non-dict crash)\n     \"[redacted:email]\": \"Nickperillo\",  # PR #8008 salvage (Discord channel-name matching + flush pending sends on shutdown)"]},{"file":"tui_gateway/server.py","hunks":["@@ -4212,12 +4212,25 @@ def _make_agent(\n     if startup_skills:\n         from agent.skill_commands import build_preloaded_skills_prompt\n \n-        skills_prompt, _loaded_skills, missing_skills = build_preloaded_skills_prompt(\n+        skills_prompt, loaded_skills, missing_skills = build_preloaded_skills_prompt(\n             startup_skills,\n             task_id=session_id or key,\n         )\n         if missing_skills:\n-            raise ValueError(f\"Unknown skill(s): {', '.join(missing_skills)}\")\n+            missing_display = \", \".join(missing_skills)\n+            # Degrade gracefully when some skills loaded; only hard-fail when\n+            # every requested skill is missing. Mirrors cli.py — a typo'd skill\n+            # name should not crash the worker and auto-block the Kanban task.\n+            if loaded_skills:\n+                logger.warning(\n+                    \"Unknown skill(s) requested, skipping: %s. \"\n+                    \"Continuing with: %s. \"\n+                    \"List available skills with `hermes skills list`.\",\n+                    missing_display,\n+                    \", \".join(loaded_skills),\n+                )\n+            else:\n+                raise ValueError(f\"Unknown skill(s): {missing_display}\")\n         if skills_prompt:\n             system_prompt = \"\\n\\n\".join(\n                 part for part in (system_prompt, skills_prompt) if part\n"]}]},{"kind":"pr","number":89763,"title":"feat(swarm): per-swarm verifier + synthesizer body and skills overrides (#34273)","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#112608","number":112608}],"category":"superseded_by_pr","implication":"superseded"},"merged":false},{"kind":"pr","number":112608,"title":"feat(swarm): per-swarm verifier + synthesizer body and skills overrides (#34273)","url":null,"state":"open","close_reason":{"refs":[{"kind":"pr","value":"#53577","number":53577},{"kind":"pr","value":"#34273","number":34273},{"kind":"pr","value":"#53577","number":53577}],"category":"duplicate_of","implication":"duplicate"},"merged":false}],"trust":{"default_tier":"verified","includes_suggested":false}}