name: hermes-kanban title: Hermes Kanban — Setup & Task Architecture description: Configure and organize Hermes Kanban boards with proper task hierarchy for enterprise/IT-BA workflows. Covers board naming conventions, task ID dot-notation, dependency linking pitfalls, and profile-based assignment. trigger: | - User wants to set up / restructure a kanban board - User asks about task hierarchy or parent-child relationships - User needs to decompose a project into sub-tasks on the board - User complains about approval gate bypass or chain reaction domains: - hermes-agent - task-management - kanban
🚫 DO NOT hardcode department mapping anywhere. The absolute source of truth is config/departments.json under /opt/ai-os/products/ceo/.
config/departments.json ←── SSOT (The only place to edit)
│
├── hermes kanban create ── CLI source of truth for task creation.
└── AGENTS.md ── DERIVED DOCS. Mirror of the JSON content.
json.load or python3 -c ...) to fetch it.update_departments.py or similar. If a script needs to know the mapping, it should read the JSON at runtime.__init__.py and delete the plugin rather than keeping a "shell" that does nothing.hermes kanban create as the single source of truth for Kanban task creation. Do not keep parallel wrapper scripts like create_kanban_task.sh unless they add verified value that the CLI cannot provide./kanban-create is acceptable only if it is truly registered and routes to the same CLI path. Do not invent or document a shortcut that is not actually wired into the command registry.Symptom: You set orchestrator to manual and write DỪNG LẠI (STOP) instructions in the task description. However, the system still auto-promotes/auto-executes downstream tasks.
Cause: The background kanban-server.service systemd service is active and runs its own autonomous dispatching/promotion cycles, ignoring the manual task body gates.
Fix: Stop and disable the service to prevent any automated board-state transitions:
systemctl stop kanban-server.service
systemctl disable kanban-server.service
Once disabled, all task state updates (todo -> ready -> running -> done) must be handled manually via SQLite command line or direct Python scripts.
[Review] or [Duyệt] lanes are completed by AI workers automatically, bypassing the CEO's mandatory human-in-the-loop validation.[Review] task (e.g., INGEST.01.RV), and because it has a valid worker role (r-and-d), the dispatcher automatically triggers the worker to "complete" the task.kanban_complete instead of calling kanban_block and asking for unblock.ceo or admin (a profile that lacks worker execution capabilities), preventing the dispatcher from spawning an AI agent to run them.[Review], [Duyệt], etc.) must start in blocked status or transition to blocked immediately after the worker finishes the preparation/analysis phase. The worker MUST call kanban_block with the proposal body, leaving the task in the [TẮC] (Blocked) lane for CEO audit.Unblock / Complete buttons via the task detail modal/popover. Never make the CEO rely on CLI for basic task approval.hermes kanban list to confirm assignee is correctly routed away from execution profiles for review-only tasks.hermes kanban show <task_id> on all related tasks (umbrella + siblings + children).blocked status and the blocker is resolvable by the main agent (not waiting on user input), resolve it immediately rather than escalating. If blocker needs user input, report it in the same message — never let the user find a blocked task on the board before you've told them about it.hermes kanban show on the umbrella + any linked siblings to ensure nothing is silently blocked.hermes kanban show on all relevant tasks (umbrella + children/siblings) to check for blocked status.blocked and the blocker is a system dependency that you can resolve yourself (e.g. status transition, link update), resolve it immediately. Do not escalate to the CEO.blocked and requires user input, report it in the same message as your action confirmation. Do not let the user discover a blocked task on their own.undefined strings), the board's rendering logic or data-merging logic is likely broken. Check kanban_server.py for duplicated functions or data-fetching logic and patch it immediately. Do not accept a broken board UI./files/. Use this to verify your changes or inspect task-related docs without needing to manually read_file every time.._* (Apple Double) files or duplicate configs (like SOUL.md inside profiles), sanitize them immediately to keep the repo backup clean and the instance behavior predictable (SOUL.md must only exist globally).unblock returns a task to ready, but if there's a hidden dependency or dispatcher lag, it might not start running.hermes kanban show <task_id> to confirm it is no longer blocked. Then check the dependent tasks too.hermes kanban show and report the current state in the same turn.done but the next dependency is now the real blocker, say so explicitly and continue the flow./files/ and verify with curl or browser access before sending./opt/ai-os/products/ceo or another allowed root, then resend the corrected URL.done because the "work is finished", even though the user asked to "review at the end" or "approve before finishing".done means "I am finished with my part", but in this system, done means "The CEO has accepted the result and the task is closed".kanban_complete. It MUST call kanban_block(reason="Chờ CEO duyệt", kind="needs_input") and report the deliverable.- **Nhóm:** lines and normalize section headers._clean.md or _view.html unless the user explicitly asks for a permanent separate copy. The web server (port 9120) should handle the "view" layer dynamically (e.g. via Sidebar ToC) without mutating the source.done, but the generated ToC in the web viewer is not clean, contains duplicate headings, or includes irrelevant markdown elements.kanban_server.py.### ## Nhóm: ...).h1, h2, h3) that clearly represent distinct sections.done or blocked for review. If browser_navigate is unavailable, use curl and parse the HTML to check for expected ToC structure.references/cron-kanban-orchestrator.md for the Static Kanban Pipeline & Cron Job Orchestrator pattern used in multi-loop data-sync research tasks, including how to prevent dispatcher hijack or auto-claim loops.references/kanban-telemetry.md for the reporting pattern that forces a Telegram update after each phase, including Funnel links and pre-loop handoff wording.references/markdown-toc-rendering.md for the correct pattern to extract and render Table of Contents from Markdown using the Python markdown library (essential for dynamic file serving).references/kanban-web-comment-visibility.md for the pattern where task comments do not show in the web viewer unless merged into the task body.references/kanban-server-rendering-patterns.md for board-selector, sort-by dropdown, max-5 collapse/expand, and task-detail-page patterns built in session 2026-07-17.references/multi-dashboard-sync.md for the common mismatch between the custom 9120 board and the official dashboard.Sub-agent reports are not sufficient evidence. A sub-agent may report "file deleted" but only have removed it from the working tree without committing and pushing. Always verify against the actual remote service.
When the task involves external services (GitHub, API, web): 1. Commit and push the change locally. 2. Verify using the actual remote URL or API endpoint (curl, gh api). 3. Only then close the Kanban task.
Example — verifying SOUL.md deletion:
# ❌ INSUFFICIENT: sub-agent says "done"
"đã thấy soul được remove khỏi profile"
# ✅ CORRECT: verify remote before marking done
curl -s -o /dev/null -w "%{http_code}" "https://raw.githubusercontent.com/.../SOUL.md"
# Must return 404; 200 means the remote is out of sync
if [ "$(curl -s -o /dev/null -w '%{http_code}' 'https://raw.githubusercontent.com/.../SOUL.md')" = "404" ]; then
hermes kanban complete t_xxxxx
else
hermes kanban block t_xxxxx "Remote NOT in sync — curl returned 200, file still exists"
fi
Why this matters (from session 2026-07-14):
- User found profiles/it-ai/SOUL.md still on GitHub despite sub-agent claiming "done"
- Root cause: sub-agent deleted file locally but never pushed to remote
- Fix: commit + push + verify raw URL → then mark complete
- User frustration: "sao cứ báo là done rồi" — because agent trusted sub-agent without verifying remote
Khi pipeline có bước Proposal/Review dành cho CEO: - Background worker làm các bước tiền đề (phân tích, nghiên cứu) tự động — không thông báo từng bước - Chỉ block task ở bước proposal, đưa CEO review + approve - Sau CEO approve → tiếp tục build → test → complete
# Pattern:
# Step A (prep, worker chạy ngầm) → propose (block) → CEO duyệt (unblock) → build → test
# Không gọi CEO lúc Step A đang chạy
# CEO message: "chỉ cần đưa tôi ở bước proposal thôi, còn lại tự ngầm"
If a task lookup unexpectedly returns no such task or a state-transition command says the task is unknown, verify the active board first. A task can exist on one board while the CLI is pointed at another.
Recovery pattern:
1. Run hermes kanban boards list to identify the active board.
2. Switch explicitly with hermes kanban boards switch <slug> before any reassignment or state transition.
3. Re-run hermes kanban show <task_id> to confirm the task is visible on the intended board.
4. Then perform assign, block, unblock, or complete.
Why this matters: in this session, the task was visible only after switching from an unrelated board to nv-office; assign succeeded, but complete/block failed until the board context was corrected. Also in this session, when claiming a task under the active board research-hub, if parent dependencies are still running (like t_53eca8c7), claim will fail with parents_not_done. If you need to force start/claim the task (e.g. you are performing manual fact-checking / verification while the parent review task is running), you must explicitly unlink them with hermes kanban unlink <parent_id> <child_id>, manual-promote with hermes kanban promote <task_id> --force, and then perform the claim action.
Related verification: after changing assignee for a review gate, immediately show the task again so the board state and assignee are confirmed together.
Symptom: You promote a task to ready using --force, but trying to claim it immediately fails with cannot claim <task_id>: status=todo lock=(none) or claim_rejected {'reason': 'parents_not_done'}.
Root Causes:
1. Runtime Dependency Check: The claim command enforces parent dependency checks at runtime. Even if a task is manually promoted to ready, if its parent tasks are not in done or archived status, the claim will be rejected and the task may revert to todo.
2. Profile/Assignee Mismatch: The terminal's active profile (e.g., default) does not match the task's assignee (e.g., reviewer). The environment variable HERMES_SESSION_PROFILE overrides the active profile selected via hermes profile use and can cause silent mismatches.
3. Todo/Lock State: If a task is in todo status on the board and has no active runner lock, direct execution claims will fail. It must be in ready (promoted) and you must assign it to your profile first.
Fix:
1. Unlink Parents: If you must work on the child task out of order, unlink it from the running parent task using hermes kanban unlink <parent_id> <child_id>, promote it with hermes kanban promote <task_id> --force, and then claim.
2. Match Profile & Assign: Assign the task to your target profile. Confirm the assignee in hermes kanban show <task_id>. Verify your active profile via hermes config show. If they mismatch, switch profile and explicitly export the session profile:
bash
hermes profile use <assignee>
export HERMES_SESSION_PROFILE=<assignee>
3. Claim: Run hermes kanban claim <task_id>. If it still fails with cannot claim: status=todo, double check that the task status is indeed ready and the assignee is correct. If the task is blocked by a running parent that you cannot unlink, you must wait for the parent to finish or force promote the task to ready before claiming.
references/task-board-recovery.md for the Python sqlite3 recovery pattern when the CLI cannot reach a task but the row exists in the board DB.When ALL tasks in a pipeline/umbrella are done (whether by spawned workers or direct agent execution), the agent MUST immediately send a final deliverable summary to the CEO in the current conversation. Do not wait for them to ask "tiến độ tới đâu rồi".
When reassigning a research or approval task to ceo, do not just change assignee and write "ready for review". The CEO needs a review packet on the task itself:
1. A clean clickable Markdown link to the exact deliverable file.
2. The specific review question or decision gate.
3. A short list of claims, sources, or assumptions to verify.
4. The current QA status and any caveats.
For this user's environment, file links MUST use the public Tailscale funnel format:
https://vmi3427693.tail8c1aaf.ts.net/files/<absolute_path>
Example:
[research_brief.md](https://vmi3427693.tail8c1aaf.ts.net/files/opt/ai-os/products/ceo/content/research/tourism_benchmarking/research_brief.md)
Never use plain http://100.71.157.103:9120 links in CEO-facing task comments. Plain URLs and private IP links force copy/paste and break mobile review flow.
To prevent context overflow and subagent degradation in multi-country research tasks, avoid combining all countries or too many steps into a single phase or single long task. Split large research pipelines into smaller, bite-sized tasks (e.g. separate Brief, separate extraction, separate Gap analysis, separate report) and link them appropriately. This keeps each run focused and within limits.
This applies even if the agent executed the work directly in the same conversation (not via spawned workers). The CEO expects a structured handoff, not silence followed by "đã xong hết rồi" as a reaction to being asked.
User's exact frustration (from session): "tiến độ tới đâu rồi làm xong hay chưa sao cũng ko thấy báo cáo gì" — this is a signal that the agent finished but failed to wrap up. Never let this happen.
When the trigger fires:
- A hermes kanban create batch completes → summarize all created tasks
- A hermes kanban complete is called on the last task in a pipeline → summarize the whole pipeline
- A background process finishes with tasks now all done → poll and summarize
- Negative example: agent finishes WR.11.03→11.05 (all done), but says nothing → CEO has to ask "tiến độ tới đâu rồi" ❌
The summary must include: - Which tasks completed (id + title + status) - Deliverable locations (absolute file paths — SOUL.md, config.yaml, etc.) - How to verify or use the result (e.g. CLI command to test, URL to open) - What's next (e.g. "Personality đã active — dùng /personality policy_researcher ở mọi thread")
## ✅ Hoàn thành WR.11
| Task | Kết quả |
|:-----|:--------|
| WR.11.03 | ✅ Proposal |
| WR.11.04 | ✅ Build — SOUL.md tại /root/... |
| WR.11.05 | ✅ Test — OK trên cả 2 thread |
## 📦 Dùng ngay
- `/personality policy_researcher` — mọi thread
- SOUL.md đã cập nhật cho R&D profile
Do NOT ask the CEO "đã xong chưa/có cần gì nữa không" — they expect you to report proactively and completely, then wait for their next instruction.
When renaming task titles to fix numbering (e.g. Proposal should be WR.11.03, Build should be WR.11.04), the task ID never changes — only the title changes. This can cause confusion:
Pattern đúng:
# Xác định task nào là Proposal, task nào là Build trước
python3 -c "
import sqlite3
c = sqlite3.connect('/root/.hermes/kanban/boards/nv-office/kanban.db')
rows = c.execute('SELECT id, title, status FROM tasks WHERE title LIKE \"%WR.11%\"').fetchall()
for r in rows: print(f'{r[0]}: {r[2]} — {r[1]}')
"
# Chỉ swap title khi thực sự cần, và verify bằng list
hermes kanban list
Hermes Dashboard (port 9119) đọc mặc định board default, không phải board nv-office. Khi user thấy dữ liệu không khớp:
- Không đổ lỗi cache — kiểm tra tenant selector trên giao diện Dashboard
- Giao diện Dashboard có dropdown TENANT ở góc trên bên trái
- User cần chọn đúng board nv-office để thấy dữ liệu chính xác
# Xác nhận nhanh DB nào đang dùng cho board nào:
# Dashboard mặc định: /root/.hermes/kanban.db (default board)
# NV-Office board: /root/.hermes/kanban/boards/nv-office/kanban.db
Không bao giờ hỏi user "anh đang xem dashboard 9119 hay 9120" — họ không phân biệt được. Thay vào đó kiểm tra chính mình bằng SQLite query và hướng dẫn họ chọn đúng tenant.
Khi tạo một board mới cho workstream riêng (ví dụ brand-monitoring), user rất dễ nói "không thấy task trên Kanban" hoặc "bạn có thể unblock được không" nếu agent đứng ở board cũ (nv-office) hoặc không nói rõ task đang nằm ở board nào.
Pattern đúng:
1. Sau hermes kanban boards create <slug> và switch <slug>, phải báo rõ board slug đang dùng.
2. Khi gửi task ID cho user, luôn nói rõ task thuộc board nào để họ xem đúng tenant/board.
3. Khi thao tác CLI (show, unblock, comment) báo unknown task hoặc no such task, kiểm tra ngay hermes kanban boards list để xem current board trước khi kết luận lỗi.
4. Luôn switch <slug> về đúng board rồi mới thao tác (unblock, comment, show).
Ví dụ thực chiến:
- Tạo board brand-monitoring và tạo task t_7f5461eb trên board đó
- Khi user yêu cầu unblock, nếu current board quay về nv-office, lệnh unblock t_7f5461eb sẽ fail với no such task
- Cách xử lý chuẩn: hermes kanban boards list → phát hiện current board là nv-office → hermes kanban boards switch brand-monitoring → hermes kanban unblock t_7f5461eb
~/.hermes/SOUL.md, which is a symlink to /opt/ai-os/products/ceo/SOUL.md.SOUL.md or soul.md inside any profile directory (~/.hermes/profiles/*/ or /opt/ai-os/products/ceo/profiles/*/). They cause identity divergence.SOUL.md files, delete them. If persona-specific behavior is needed, use hermes config set personalities.<name> '<prompt>' or profile-specific config files, but never SOUL.md.distributions/ (like /opt/ai-os/products/ceo/distributions/*/SOUL.md) are read-only references; do not mutate them.find /root/.hermes/profiles/ /opt/ai-os/products/ceo/profiles/ -iname "soul.md" -type f -delete) to keep folders sanitized.Layered identity architecture (bottom to top):
| Layer | Scope | File / Command |
|:------|:------|:---------------|
| SOUL.md | Whole instance | ~/.hermes/SOUL.md |
| Profile Description | Per department | hermes profile describe <name> --text "..." |
| AGENTS.md | Per project repo | ./AGENTS.md |
| /personality | Per session (overlay) | /personality <name> in chat |
Verification:
grep -A 5 '<personality-name>' /root/.hermes/config.yaml
# Ensure no local profile identity files remain:
find /root/.hermes/profiles/ -name "*SOUL.md"
Reference file: skill_view(name='hermes-kanban', file_path='references/personality-soul-integration.md') — decision framework for partitioning content between SOUL.md and personality configs.
hermes config set personalities.<name> '<prompt>' has an implicit size limit from the CLI argument parser — very long prompts with multi-line content may be silently truncated or rejected.
Symptoms: The personality appears in config.yaml but is truncated (missing sections). The /personality command activates but the behavior doesn't match the full prompt.
Mitigation: Keep the personality prompt concise — focus on style, domain knowledge, and writing rules. Reserve detailed knowledge (terminology tables, long examples) for SOUL.md. The config.yaml personality is meant to be a lightweight behavior modifier, not a full knowledge dump.
If truncation happens: Edit ~/.hermes/config.yaml directly with a text editor (but note the patch tool may refuse for security — use hermes config set or the file editor with caution).
html variable name shadowingIf kanban_server.py crashes with: Error: cannot access local variable 'html' where it is not associated with a value
Check the top of the file for:
import html # ← Python stdlib module
And then in the same file, a local variable named html:
html += `...` # ← string concatenation using 'html' as a variable
The local variable html shadows the imported module html. If the local variable is assigned but the assignment branch doesn't execute (e.g. an exception before the assignment), Python raises UnboundLocalError on the next reference.
Fix: Rename either the import or the variable:
- Use import html as htmllib (then call htmllib.escape())
- Or rename the local variable to html_buf or output_html
Symptom: User questions how a Kanban task "understands its mission" or asks "where personality is defined" for a given task/phase. Kanban task bodies are overly brief, relying on external delegation context that is not persistent.
Root Cause:
1. Over-reliance on delegate_task's goal/context parameters to convey full task instructions and agent Personality. This makes Kanban tasks non-self-contained and vulnerable to context loss.
2. Lack of explicit Personality mapping in the overall research plan or task templates.
Fix:
1. Self-contained Task Bodies: For every Kanban task, ensure its body field is comprehensive and self-contained. This includes:
* CONTEXT: Absolute paths to critical reference files (research_plan.md, research_output_template.md, etc.).
* PERSONALITY: Explicitly assign the Personality (e.g., Policy Researcher, Institutional Strategist) required for the agent executing this task.
* MỤC TIÊU (Objectives): Clear, detailed goals and scope for the task.
* OUTPUT: Required deliverable files, format, and storage locations.
* MANUAL GATE: Clear instructions for pausing and awaiting human review.
2. Explicit Personality Map in Research Plan: Define a "Personality Map" section in the top-level research_plan.md (or similar project plan) that assigns a specific personality to each major pipeline phase. This provides a central reference.
3. Template Integration: Embed the required personality directly into phase-specific templates (e.g., research_output_template.md) for phases where a particular writing style or analytical approach is critical.
This ensures tasks are robust, transparent, and consistently executed with the desired voice and analytical rigor.