Found on graphifyy 0.9.26 (uv tool install, Python 3.11, Linux), running graphify <dir> --backend claude-cli followed by graphify export obsidian --graph graphify-out/graph.json --labels graphify-out/.graphify_labels.json --dir <vault> on a small mixed corpus (4 code files + 2 markdown docs, Spanish source, 54 nodes / 78 edges / 18 communities).
Summary
to_obsidian() sanitizes community names with _obsidian_tag() when it writes the tag into each note, but writes the .obsidian/graph.json colorGroups query from label.replace(' ', '_') — unsanitized. The two disagree for any community name containing a character outside [a-zA-Z0-9_\-/], and that colorGroup silently matches zero notes. The community renders uncolored in graph view while its siblings are colored, with no warning printed.
Where
graphify/export.py
# line 99 — used for the tag inside each note
def _obsidian_tag(name: str) -> str:
return re.sub(r"[^a-zA-Z0-9_\-/]", "", name.replace(" ", "_"))
# line 735 — used for the graph-view color group. Not sanitized.
"query": f"tag:#community/{label.replace(' ', '_')}",
Reproduction
Any corpus where the community labeler produces a name with &, +, (, ) or a diacritic. In my run, community Product & Vale Lookup:
- note frontmatter and inline tag:
#community/Product__Vale_Lookup
.obsidian/graph.json: "query": "tag:#community/Product_&_Vale_Lookup"
Standalone check of the two code paths:
import re
def obsidian_tag(n): return re.sub(r'[^a-zA-Z0-9_\-/]', '', n.replace(' ', '_'))
def colorgroup(n): return n.replace(' ', '_')
for name in ['Product & Vale Lookup', 'C++ Parser', 'Auth (v2)', 'Créditos', 'I/O Layer']:
print(f'{name!r:24} note={obsidian_tag(name):22} config={colorgroup(name):22} '
f'{"ok" if obsidian_tag(name) == colorgroup(name) else "MISMATCH"}')
'Product & Vale Lookup' note=Product__Vale_Lookup config=Product_&_Vale_Lookup MISMATCH
'C++ Parser' note=C_Parser config=C++_Parser MISMATCH
'Auth (v2)' note=Auth_v2 config=Auth_(v2) MISMATCH
'Créditos' note=Crditos config=Créditos MISMATCH
'I/O Layer' note=I/O_Layer config=I/O_Layer ok
Four of five realistic community names break. & in particular is very common in LLM-generated community names (Product & Vale Lookup, Auth & Session, Parsing & Validation).
Expected
Every colorGroup query matches the tag actually written into the notes.
Suggested fix
One line — reuse the existing sanitizer:
"query": f"tag:#community/{_obsidian_tag(label)}",
A regression test asserting that every colorGroups[].query in the emitted .obsidian/graph.json matches at least one #community/... tag present in the emitted notes would pin this permanently, and would also catch the reverse drift if _obsidian_tag ever changes.
Note on diacritics
Créditos → Crditos is a separate cosmetic wart of _obsidian_tag (it deletes accented characters rather than transliterating them). Obsidian accepts Unicode letters in tags, so Créditos would be a legal tag as-is. _strip_diacritics() already exists in the same module. Not filing separately — mentioning in case you want to widen the allowed set while touching this function.
Found on graphifyy 0.9.26 (uv tool install, Python 3.11, Linux), running
graphify <dir> --backend claude-clifollowed bygraphify export obsidian --graph graphify-out/graph.json --labels graphify-out/.graphify_labels.json --dir <vault>on a small mixed corpus (4 code files + 2 markdown docs, Spanish source, 54 nodes / 78 edges / 18 communities).Summary
to_obsidian()sanitizes community names with_obsidian_tag()when it writes the tag into each note, but writes the.obsidian/graph.jsoncolorGroups query fromlabel.replace(' ', '_')— unsanitized. The two disagree for any community name containing a character outside[a-zA-Z0-9_\-/], and that colorGroup silently matches zero notes. The community renders uncolored in graph view while its siblings are colored, with no warning printed.Where
graphify/export.pyReproduction
Any corpus where the community labeler produces a name with
&,+,(,)or a diacritic. In my run, communityProduct & Vale Lookup:#community/Product__Vale_Lookup.obsidian/graph.json:"query": "tag:#community/Product_&_Vale_Lookup"Standalone check of the two code paths:
Four of five realistic community names break.
&in particular is very common in LLM-generated community names (Product & Vale Lookup,Auth & Session,Parsing & Validation).Expected
Every colorGroup query matches the tag actually written into the notes.
Suggested fix
One line — reuse the existing sanitizer:
A regression test asserting that every
colorGroups[].queryin the emitted.obsidian/graph.jsonmatches at least one#community/...tag present in the emitted notes would pin this permanently, and would also catch the reverse drift if_obsidian_tagever changes.Note on diacritics
Créditos → Crditosis a separate cosmetic wart of_obsidian_tag(it deletes accented characters rather than transliterating them). Obsidian accepts Unicode letters in tags, soCréditoswould be a legal tag as-is._strip_diacritics()already exists in the same module. Not filing separately — mentioning in case you want to widen the allowed set while touching this function.