Use when generating architecture/concept diagrams for entities in ~/wiki/entities/. Produces Excalidraw files (.excalidraw), Mermaid diagrams, and optional AI-generated cover images. Scans entities to score visualizability, lets the user pick candidates, then generates the three-artifact stack per entity.
Use when generating architecture/concept diagrams for entities in ~/wiki/entities/. Produces Excalidraw files (.excalidraw), Mermaid diagrams, and optional AI-generated cover images. Scans entities to score visualizability, lets the user pick candidates, then generates the three-artifact stack per entity.
Generates diagrams for entities in ~/wiki/entities/. Each chosen entity gets three artifacts:
Excalidraw (.excalidraw file in assets/entities/) — primary visual. Hand-drawn aesthetic + perfect Virgil-font text + editable in browser. Hand off to humans, embed in Obsidian via plugin.
Mermaid (in-body in the entity's .md file) — knowledge source. Version-controlled, lint-checkable, searchable. The "source of truth" representation.
AI cover image (PNG in assets/entities/) — optional decoration. Hand-drawn marker style via agnes-ai skill. Text may be garbled — use only as social-card / hero image, not for reading.
This skill does NOT do article ingestion, scoring, or evaluation. It assumes entities already exist. Pair it with wiki-pipeline for end-to-end ingest+visualize.
When to Use
Use this skill when the user:
Says "visualize entity X" or "add diagram to entity Y"
Says "generate diagrams for all the entities" (or a filtered subset)
After a batch ingest: "now visualize the new entities"
Wants a quick "which entities would look good as diagrams?" answer (run the scan step only)
Do NOT use for:
Non-entity pages (concepts, queries, comparisons have their own conventions)
Pages with no real structure to visualize (single-fact entries, news digests)
Replacing the entity's prose — the diagram supplements, not replaces
Operating Contract
Excalidraw is primary visual. It has perfect text rendering (Virgil font, real OpenType glyphs) and is editable. The user explicitly preferred this over AI-generated images (response: "封面图的字体不是很好").
Mermaid is knowledge source. It lives in the entity's .md body, gets version-controlled, can be searched. Always generated.
AI cover image is optional decoration. Only generate if the user asks, or if the entity is "presentation-grade" (will be used in talks / blog posts / social cards).
One commit per entity. Don't batch 10 entities into one commit — Phase 2 closeout convention is one entity per commit for clean history.
Lint must pass before commit. Run node ~/wiki/scripts/wiki-lint.mjs ~/wiki and confirm 0 NEW errors (pre-existing errors are out of scope).
Index update is NOT needed. Entities are already in index.md. The assets/entities/*.excalidraw and assets/entities/*.png files don't need separate index entries — they live alongside the entity.
Three Modes
Mode 1: Scan + Rank (no generation)
Score all entities for "visualizability" and output a ranked candidate list. No files written, no commits.
Generates three artifacts and commits them as one Phase 2 closeout:
Reads ~/wiki/entities/<slug>.md
Extracts frontmatter + body
Calls LLM (MiniMax-M2.7 via api.minimaxi.com/v1/text/chatcompletion_v2) to generate Excalidraw JSON and Mermaid code in parallel from a structured prompt
Validates the Excalidraw JSON against the schema
Optionally uploads via ~/.hermes/skills/creative/excalidraw/scripts/upload.py to get a shareable link
Optionally calls ~/.hermes/skills/creative/agnes-ai to generate the cover image
Runs scan → picks top N above score threshold → visualizes each in sequence (one commit per entity).
Safety: A --dry-run flag shows the plan without committing. Always dry-run first for N > 5.
The LLM Prompt (the heart of the skill)
The skill sends the entity body to MiniMax-M2.7 with a structured prompt requesting both Excalidraw JSON and Mermaid code in one response. See references/llm-prompt-template.md for the full template.
Key design choices in the prompt:
Asks for 2-9 visual elements (sweet spot for diagram clarity)
Asks for labels in BOTH English and Chinese (Mermaid handles both well; Excalidraw text elements can be any language)
Asks for a one-sentence summary that goes into the Excalidraw title
Asks for explicit colors per layer/category (so the LLM doesn't default to "all blue")
Asks for a legend if there are more than 3 visual categories
Validates the JSON output before accepting (catches the common LLM error of adding comments or trailing commas)
Common Pitfalls
Visualizing the wrong entities. Not every entity benefits from a diagram. News digests, single-fact entries, and pure opinion pieces score 0-3 and should be skipped. Always run the scan first.
Generating too many elements. The LLM will happily generate 25-node diagrams. That's too dense. Cap at 9 elements (6 layers + 3 projects is plenty). If the entity has more, group them.
Excalidraw JSON drift. The LLM will sometimes add label: { text: "..." } (invalid) instead of using the container-binding pattern. The validator catches this. If validation fails, retry with temperature=0.3 and a stricter prompt — the second attempt usually works.
Forgetting the shareable link. Excalidraw files are useless without a way to open them. Always upload via the skill's scripts/upload.py (requires cryptography Python package) to get a shareable link.
AI cover image text typos. The user explicitly flagged this. The cover image is decorative only. Add a markdown caption on the Mermaid image warning readers. Never put critical information in the AI cover.
One commit per entity, not per artifact. Don't commit Excalidraw, then Mermaid, then cover as 3 separate commits. One Phase 2 closeout = one commit. This is the wiki's convention.
Lint pre-existing errors. Don't try to fix unrelated lint errors in the same commit. The convention is "0 new errors, not 0 total errors". The skill now distinguishes new vs pre-existing errors automatically.
Index.md corruption. When inserting backticks/quotes into entity frontmatter, the patch tool may add |- prefix corruption. Always run sed -i '' 's/^|- /- /' index.md after any index.md patch.
Excalidraw text positioning. The skill uses approximate x/y for text elements; Excalidraw recalculates on load based on containerId. The file will look slightly off in raw JSON view but render correctly in the browser. Don't manually adjust text positions after generation.
Mermaid graph TB vs flowchart TB. Use flowchart TB for new diagrams — graph is deprecated. The prompt template uses flowchart; if you see graph in output, regenerate.
LLM hallucination (critical). LLMs sometimes ignore the actual entity content and produce a generic "central node with branches" diagram with completely wrong labels (verified 2026-06-02: a Sequoia/AGI entity came back as a "Solar System" diagram with Sun+planets). The skill's validate_and_clean function now checks that the LLM's returned title overlaps with the entity's title — at least 2 meaningful terms in common. If not, the skill aborts with a clear error message and the user can re-run with stricter prompt or build by hand.
Implementation detail (in validate_and_clean):
Strip common stop words from BOTH titles (English and Chinese — STOP list lives in the function)
If len(overlap) < 2 AND len(entity_meaningful) >= 3 → abort
The threshold of 2 chars is empirical — tested on AGI/Solar (overlap=0, aborts) and 1Password/Securing AI Agents (overlap=4, passes)
Template loader bug (fixed 2026-06-02). The prompt template in references/llm-prompt-template.md is wrapped in a fenced code block preceded by a prose line ("This is sent to..."). The original regex r'## The Prompt\n+(```\n)?(.+?)(?=\n## )' extracted only the prose-intro line, not the full prompt. The full prompt was 461 chars instead of 2334. Symptom: the LLM gets a generic "generate a diagram" prompt with no entity content, and returns something completely unrelated. Fix: use a prose-prefix-aware regex that explicitly skips the intro line before matching the fenced block.
How to detect this in a future session: if the script's prompt length comes out under ~1000 chars (it should be 2000+), the template loader is broken. Quick check: python3 -c "from visualize_entity import build_llm_prompt; print(len(build_llm_prompt('test',['t'],'b',1.0)))". Should print ~2300. If it prints ~460, the template loader regressed.
Cover image timeout (split-commit pattern). The skill uses a 60s urllib.request.urlopen timeout for the Agnes call. Long prompts (>2000 chars) can exceed this. The skill's generate_cover_image function catches the timeout and prints "Cover generation failed: ..." but the script continues to commit Excalidraw + Mermaid anyway (good — partial work is preserved). The cover image is then generated manually in a follow-up commit.
Established recovery workflow (verified 2026-06-02 on 1password-securing-ai-agents-machine-identities):
Cover generation times out, script continues to commit without it
User runs a separate python3 -c "urllib curl ..." with a shorter prompt
Downloads the PNG, saves to assets/entities/<slug>.png
Patches a ### 封面图 section into the entity body via patch tool
Commits as commit #2 (visualize: <slug> (cover image added))
This results in 2 commits per entity when covers are slow, 1 commit when covers succeed. Both are valid Phase 2 closeouts. Don't try to "fix" this by re-running the whole skill — that would re-generate the Excalidraw and create a diff.
To prevent timeouts proactively: keep the cover prompt under 1500 chars. The skill's build_cover_prompt is verbose by default; trim if the entity is long.
Linting interactive prompt blocks automation. The original skill called input("Continue anyway? [y/N] ") when lint failed. In a non-interactive terminal, this crashed with EOFError after the LLM + file work was already done. The skill now classifies errors as "new" vs "pre-existing" automatically and proceeds without prompting. If you see EOFError in logs, the lint-classification logic is broken — patch run_wiki_lint in visualize_entity.py.
Verification Checklist
After running Mode 2 or 3 on an entity:
assets/entities/<slug>.excalidraw exists, is valid JSON, parses as Excalidraw envelope
Element count is 5-50 (sweet spot, not too sparse / not too dense)
Shareable link generated and pasted into entity's 可视化 section
entities/<slug>.md has a ## 可视化 section (or appended to existing one)
User feedback: cover image text was poor (LLM-rendered) → reordered to put Excalidraw as primary
Lesson baked into the skill: Excalidraw > AI cover for primary visual.
How to Run This Skill (quick reference)
User says: "visualize entity X" or "add diagram to entity X"
→ Mode 2: python3 scripts/visualize_entity.py ~/wiki entities/x --with-cover-image
User says: "which entities would look good as diagrams?"
→ Mode 1: python3 scripts/scan_visualizability.py ~/wiki
User says: "generate diagrams for all the entities"
→ Mode 1 first, then Mode 3 with --min-score 8
→ Always dry-run first: --dry-run --top 5 to show the plan
User says: "regenerate the cover for entity X (the text was bad)"
→ Don't. The cover is decorative. Edit the Mermaid in the entity, or regenerate the Excalidraw.
→ Only regenerate the cover if the user explicitly asks for a new hero image.