Install
$ agentstack add skill-lexbritvin-obsidian-skills-pack-obsidian-graph ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Obsidian Graph view
Global graph configuration lives in .obsidian/graph.json. Local graph (Graph view opened from a single note) lives in .obsidian/workspace.json and does not inherit from global. This skill covers global graph unless explicitly noted.
For diagnosing what's wrong with a graph (over-connection, render-only edges, false categories), use the paired obsidian-graph-audit skill first.
Workflow when the user asks "configure my graph"
- Ask or read intent first. What's bothering them, or what do they want to see? Color groups without a goal are pure aesthetics — skip them.
- ⚠️ Have the user close Graph view (or quit Obsidian). This is mandatory — Obsidian rewrites
graph.jsonwhen Graph view closes, wiping external edits. See Caveats. - Read the current
.obsidian/graph.json. Don't reset settings the user has tuned (especiallyscale). - Measure vault size:
find . -name '*.md' -not -path './.obsidian/*' -not -path './.trash/*' -not -path './.claude/*' | wc -l. Forces depend on this. - Apply minimum changes, explain each. 14 color groups on 600 notes is too many — 3-8 is the proven range.
- Keep only what adds signal. Filter > group when you don't want to see something; group > filter when you want to differentiate.
- Verify decimal RGB math. A wrong byte in a color value silently renders as a different color. Always round-trip HEX↔decimal (see below).
- Have the user open Graph view after edits. Changes take effect on next open.
Full schema of graph.json
20 fields. Source: community gist on syncing graph settings, example repo. Obsidian has no official schema document.
Filters block
| Field | Type | Purpose | |---|---|---| | collapse-filter | bool | Whether the Filters block is collapsed in the UI | | search | string | Filter query (same syntax as core Search) | | showTags | bool | Tag nodes shown as separate nodes | | showAttachments | bool | Files (PNG, PDF) shown as nodes | | hideUnresolved | bool | Hide unresolved wikilinks | | showOrphans | bool | Show nodes with no connections |
Color groups block
| Field | Type | Purpose | |---|---|---| | collapse-color-groups | bool | Whether the Groups block is collapsed | | colorGroups | array | Array of {query, color} objects |
Display block
| Field | Type | Purpose | |---|---|---| | collapse-display | bool | Whether the Display block is collapsed | | showArrow | bool | Show direction arrows on edges | | textFadeMultiplier | number | 0 = labels never visible; 1 = always; ~0.5 = visible at moderate zoom | | nodeSizeMultiplier | number | 1 = default; >1 makes hubs bigger | | lineSizeMultiplier | number | 1 = default; ", "color": { "a": 1, "rgb": } }
- `a` — alpha (transparency), 0 = invisible, 1 = solid. Almost always 1.
- `rgb` — 24-bit decimal: `R*65536 + G*256 + B`.
### HEX → decimal conversion
```bash
python3 -c "h='E07B5A'; print(int(h, 16))" # → 14711642
Or manually: 0xE07B5A = 224*65536 + 123*256 + 90 = 14,711,642.
One wrong byte renders as a different color. Always round-trip:
python3 -c "n=14711642; print(f'#{n:06X}')" # → #E07B5A
Palette — pastel set
Soft, calm overall. Luminosity values are close, so 5+ groups in this set may visually merge.
| Color | HEX | Decimal | Use | |---|---|---|---| | Coral | #E07B5A | 14711642 | Active priority project | | Pink | #E36B9B | 14904219 | Personal / relationships | | Purple | #9B6BE3 | 10185699 | Habit / personal logs | | Sky blue | #5AAFE0 | 5943264 | Learning | | Green | #7BC15A | 8110426 | Lifestyle / household | | Gold | #E0C95A | 14731610 | Tech / sandbox | | Teal | #5EC1B5 | 6209973 | Planning | | Yellow | #F0D060 | 15781984 | Hubs / MOCs | | Cream | #D9C89E | 14272670 | Zettelkasten / passive | | Mustard | #C9A03B | 13213755 | External entities | | Soft gray | #8B9DA9 | 9149865 | Clippings / refs | | Muted blue-gray | #708FA8 | 7376808 | Daily | | Neutral gray | #A0A0A0 | 10526880 | Inputs / rough | | Dim gray | #666666 | 6710886 | Tag underlay |
Palette — high-contrast set
Use when 5+ pastel groups blur together. Luminosity ranges from bright (hubs) to dark (Daily) — the eye separates them.
| Color | HEX | Decimal | Use | |---|---|---|---| | Bright Gold | #E8B931 | 15252785 | Hubs (primary accent) | | Coral red | #D9583E | 14244414 | Active project (catch-all) | | Mustard | #B8861F | 12092447 | Entity type (Companies) | | Light Purple | #B47AC9 | 11828425 | Entity type (Contacts) | | Deep Purple | #7E4FA8 | 8278440 | Entity type (Concepts, MOCs) | | Saturated Green | #6FA855 | 7317077 | Lifestyle category | | Bright Cyan | #2EB5C9 | 3061193 | Other projects (catch-all) | | Cream | #D9C89E | 14272670 | Passively saved (Clippings, Meetings) | | Soft gray | #8B9DA9 | 9149865 | Reports / refs | | Dark Slate | #4A5C6B | 4873323 | Daily / archive |
Four coloring strategies
Color groups can target four different dimensions of a note. Different vaults call for different strategies; mature vaults usually mix them.
A. Folder-based (path:)
{"query": "path:\"Projects/Active\"", ...}
When to use: Project-organized vault where the folder is a meaningful unit. Each project lives in its own folder, the layout is stable.
Pros:
- Simple mental model — "everything in this folder"
- No frontmatter required
- New files inherit the color automatically
Cons:
- Doesn't capture cross-cutting concerns (hub-pages, status workflows) that span folders
- Reorganizing folders breaks the coloring
- Files in one folder may be of different types (an epic and a routine note get the same color)
B. Category-based (["categories":"X"])
{"query": "[\"categories\":\"Companies\"]", ...}
When to use: Kepano-style vault with frontmatter categories:. Category = entity type (company, contact, recipe, film). Files in one category are semantically homogeneous.
Pros:
- Color follows entity meaning, not accidental location
- A file can belong to multiple categories (multi-color via group order)
- Folder reorganization doesn't break it
Cons:
- Property-search is substring match.
["categories":"Recipe"]matches bothRecipesandRecipe Drafts. Categories must be distinct strings (see Caveats) - Requires disciplined frontmatter
- Files without categories (rough notes, drafts) are uncolored
C. Topic-based (["topics":"X"])
{"query": "[\"topics\":\"Active Initiative\"] OR file:\"Active Initiative\"", ...}
When to use: Kepano-style with topics: fields (wikilinks to epics or coordinating concepts). Useful for an active project with epic-coordinators and many files attached to each.
Pros:
- Color = semantic cluster (the epic and everything tied to it)
- Cross-folder: files from
Reports/,Interview Prep/,BootCamp/can land in one color if they share a topic - Ghost nodes work — the query reads the topic from frontmatter; it doesn't need the epic file to exist
- Sharper than path catch-all for a large active project (splits work streams visually)
Cons:
- Same substring-match caveat as
["categories":...] - Files without topics aren't colored
OR file:"X"is needed to color the epic node itself (the epic doesn't list itself as its own topic)- More groups means closer to the 14-group practical ceiling
D. Tag-based (tag:#name)
{"query": "tag:#hub", ...}
When to use: Tag taxonomy for cross-cutting concerns — hubs (#hub), statuses (#status/done), types (#moc, #evergreen). A tag describes "what role does this file play in the graph", not "what is this file".
Pros:
- Strict match (not substring, unlike property)
- Multi-dimensional — tags cross folders and categories
- Easy to add or remove ad hoc
Cons:
- Tag taxonomy can sprawl without discipline
- A bare tag with no file is an orphan node when
showTags: true - Bureaucratic for very large vaults
Mixed approach — typical for mature vaults
"colorGroups": [
{"query": "tag:#hub", ...}, // cross-cutting accent
{"query": "[\"categories\":\"Companies\"]", ...}, // entity types
{"query": "[\"categories\":\"Contacts\"]", ...},
{"query": "[\"topics\":\"Active Initiative\"] OR file:\"Active Initiative\"", ...}, // epic clusters
{"query": "[\"topics\":\"Other Initiative\"] OR file:\"Other Initiative\"", ...},
{"query": "path:\"Daily\"", ...}, // structural folder
{"query": "path:\"Projects\"", ...} // catch-all
]
Order matters — tags first (semantic role), categories second (entity type), topics third (epic clusters of the active project), paths last (catch-all). First match wins.
Choosing a strategy
| Signal | Strategy | |---|---| | Projects in Projects/X/, little frontmatter | Folder-based | | Kepano-style, categories: [[X]] everywhere | Category-based | | Active project with epics, topics: on coordinators | Topic-based | | Goal: highlight hubs / statuses / workflow stages | Tag-based | | 600+ notes, active project + entity types + epics + hubs | Mixed (all four together) |
Best practices
- Color by meaning, not by folder. Folder is one dimension; see the four-strategy section above. Pick by structure, often combine.
- 3-8 color groups, not 14. Each group is render overhead and visual noise. If 14 feels needed, the user probably wants 5 conceptual buckets, not 14 individual ones.
- Order matters. Specific queries first, broad last. First match wins.
- Filter only for active noise, not for periphery. Folders that are weakly connected (rough notes, drafts, scratch) form their own peripheral cluster and don't crowd the center. Filter is justified when nodes from a folder embed into the center and pollute important clusters — typical candidates:
Templates(if not inuserIgnoreFilters), archive tagged#archive. Before adding-path:or-tag:, ask: "are these nodes currently in the center, or on the edge?". On the edge — leave them, they give visual segregation.
- Don't show tags on the graph unless they're cross-cutting. Tags isolated to a single note become satellite-nodes with no signal. Tags that duplicate folder names add tangle without meaning. Enable
showTags: trueonly when tags form a real semantic network (#moc,#status/*, thematic concepts).
textFadeMultiplier 0means labels never visible. If you want to read names at zoom-in, set ≥ 0.3 (0.5 is a good default).
- Forces are vault-size dependent. Sane defaults for ~600 notes:
centerStrength: 0.5,repelStrength: 15-25,linkStrength: 0.7-1,linkDistance: 150-250. Larger vault → more repel + shorter links.
- Don't edit
scaleby hand. Obsidian overwrites it on every zoom. Manual edits are wiped.
- Local graph is configured separately. Local graph config lives in
.obsidian/workspace.jsonunder workspace state; it doesn't inherit from global. For shared color groups locally, install the community plugin Sync Graph Settings.
- CSS snippet for defaults, color groups for exceptions (community pattern). Set base node/tag/attachment/unresolved colors via a CSS snippet once, use color groups only for specific subsets. Less retina-burning than 8 path-based groups doing everything.
CSS classes (for snippets)
The graph renders to canvas/WebGL, but Obsidian reads CSS color rules and converts them. Use !important to override. Path: Settings → Appearance → CSS snippets.
| Class | What it colors | |---|---| | .graph-view.color-fill | Default node fill | | .graph-view.color-fill-focused | Focused node | | .graph-view.color-fill-tag | Tag node (theme-dependent: .theme-dark / .theme-light) | | .graph-view.color-fill-attachment | Attachment | | .graph-view.color-fill-unresolved | Broken link | | .graph-view.color-fill-highlight | Hover | | .graph-view.color-arrow | Direction arrow | | .graph-view.color-circle | Node ring | | .graph-view.color-line | Edge | | .graph-view.color-line-highlight | Hover edge | | .graph-view.color-text | Node label |
#HEX, rgb(), and rgba() are all supported. For transparent edges in graph view, use rgba.
Recipes
Hide noise
"search": "-path:\"Templates\" -path:\"Rough Notes\" -tag:#archive"
Focus on one project
"search": "path:\"Projects/Active\""
Color by status (tag-based)
"colorGroups": [
{"query": "tag:#status/done", "color": {"a": 1, "rgb": 8110426}},
{"query": "tag:#status/draft", "color": {"a": 1, "rgb": 14731610}},
{"query": "tag:#status/seed", "color": {"a": 1, "rgb": 9149865}}
]
Color by project (folder-based)
"colorGroups": [
{"query": "path:\"Projects/A\"", "color": {"a": 1, "rgb": 14711642}},
{"query": "path:\"Projects/B\"", "color": {"a": 1, "rgb": 10185699}},
{"query": "path:\"Notes\"", "color": {"a": 1, "rgb": 14272670}},
{"query": "path:\"Daily\"", "color": {"a": 1, "rgb": 7376808}}
]
Color by category (Kepano-style)
"colorGroups": [
{"query": "[\"categories\":\"Companies\"]", "color": {"a": 1, "rgb": 12092447}},
{"query": "[\"categories\":\"Contacts\"]", "color": {"a": 1, "rgb": 11828425}},
{"query": "[\"categories\":\"Recipes\"]", "color": {"a": 1, "rgb": 7317077}},
{"query": "[\"categories\":\"Reports\"]", "color": {"a": 1, "rgb": 9149865}}
]
Color by topic (epic clusters of an active project)
"colorGroups": [
{"query": "[\"topics\":\"Initiative A\"] OR file:\"Initiative A\"",
"color": {"a": 1, "rgb": 14904219}},
{"query": "[\"topics\":\"Initiative B\"] OR file:\"Initiative B\"",
"color": {"a": 1, "rgb": 5943264}}
]
OR file:"X" is needed because the epic node's own topics: references upstream parents, not itself.
Highlight hubs / MOCs
Tag-based — strict, recommended:
{"query": "tag:#hub", "color": {"a": 1, "rgb": 15252785}}
Folder/file-based fallback (when tags aren't in use):
{"query": "file:\"Home\" OR file:\"About\" OR path:\"Categories\"",
"color": {"a": 1, "rgb": 15781984}}
Hide infrastructure and archive via tag taxonomy
Establish: #dashboard for view pages (kanban, metrics, charts), #no-graph for logs / setup docs / configs (pure control tag), #archive for archived content.
"search": "-tag:#dashboard -tag:#no-graph -tag:#archive"
Combine with category-exclude to hide entity types not wanted on the conceptual graph:
"search": "-tag:#dashboard -tag:#no-graph -[\"categories\":\"Vacancies\"]"
Forces for a 600+ note vault
"centerStrength": 0.5,
"repelStrength": 22,
"linkStrength": 0.7,
"linkDistance": 220,
"textFadeMultiplier": 0.5,
"nodeSizeMultiplier": 1.4,
"lineSizeMultiplier": 0.8
Caveats and gotchas
- ⚠️ Obsidian rewrites
graph.jsonwhen Graph view closes. When the graph tab closes (or the app quits), Obsidian flushes its in-memory state to the file, overwriting external edits. Symptom: just-made edits are gone,close: true, andcolorGroups: [].
Procedure: either (a) Cmd+Q quit Obsidian → edit graph.json → relaunch → open Graph view; or (b) close the Graph view tab → edit → Cmd+P → Reload app without saving → open Graph view. Never edit while Graph view is open.
- Property-search is substring, not strict.
["topic"]matchestopic,parent_topic, andtopic_alternative. Don't use property search for color groups when precision matters; use tags instead. - Many color groups slow rendering. Each group is
O(notes × groups)per repaint. Above 15 gro
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: lexbritvin
- Source: lexbritvin/obsidian-skills-pack
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.