Skip to main content

static-ontology-knowledge-graph-trap

Hard-coded note_type / category enums in a knowledge system create filing cabinets, not knowledge graphs. The trap: classification looks like success (notes neatly distributed across folders) while the actual graph value (emergent connections, surprising links) stays at zero. Static ontology + LLM classifier = sophisticated tagger, not graph thinking.

Source facts

Repository
blas1n/claude-skills
Last source activity
May 5, 2026 at 13:42
Detected SKILL.md language
English
Stars
2
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions ยท Read-only preview
name
static-ontology-knowledge-graph-trap
description
Hard-coded note_type / category enums in a knowledge system create filing cabinets, not knowledge graphs. The trap: classification looks like success (notes neatly distributed across folders) while the actual graph value (emergent connections, surprising links) stays at zero. Static ontology + LLM classifier = sophisticated tagger, not graph thinking.
version
1.0.0
category
trap
# Static Ontology Trap in LLM-Backed Knowledge Systems ## When to Use Designing or reviewing any system that: - Stores user knowledge (notes, memories, conversations, documents) - Uses an LLM to classify/organize/structure that input - Has a fixed enum of categories (`note_type`, `kind`, `category`) baked into: - Folder structure (`facts/`, `insights/`, `projects/`) - Frontmatter / metadata (`type: fact`) - LLM prompts (`pick one of: idea, insight, project, ...`) - Database schemas / types - Frontend filters / colors If yes โ€” you're building a filing cabinet that LARP's as a knowledge graph. The enum is the trap. ## The Symptom Pattern You build the system. You demo it: - Import 30 mixed notes - LLM cleanly puts them into 8 folders - Demo report says "โœ“ 30 notes classified, 7 insights / 5 facts / 10 projects / ..." - Looks like success But: - User asks "show me what connects to [[Authentication]]" โ†’ no useful answer - User finds same concept duplicated across 5 folders - Cross-references between notes are limited to wikilinks the LLM happened to place IN-batch - After 6 months: 1000 notes in neat folders, zero emergent insight - User feedback: "I expected this to find connections I didn't know about. It just files things." You optimized the wrong metric. Classification accuracy is not graph value. ## Why It's Silent 1. **Classification is observable, discovery isn't.** You can write a test for "did this note get the `project` type?". You cannot easily test "did the system surface a non-obvious connection?". The visible metric drives the design. 2. **LLM compliance feels like intelligence.** Forcing the LLM to "pick from this enum" returns 100% valid answers (it's good at constrained generation). The illusion of correctness hides the lack of original output. 3. **Folders feel safe.** "Where are my facts?" โ†’ `facts/` directory. Browsable, intuitive, traditional. The org chart of knowledge feels right because it mirrors filesystems. 4. **Enum is a one-line addition that becomes a 50-file dependency.** Once `note_type` is in the schema, the prompt, the folder structure, the UI filter, the API query params, the graph view's color legend โ€” pulling it out means touching all of them. ## Why Filing Cabinet โ‰  Knowledge Graph | Filing cabinet | Knowledge graph | |---|---| | Identity = `type: X` (metadata field) | Identity = position in graph (what it connects to) | | Type chosen from fixed enum | Type emerges from clusters / communities | | Folders by type (`facts/`, `projects/`) | Flat or chronological storage | | Browsing: "show me all facts" | Querying: "what links to X" / "what bridges A and B" | | Static โ€” type doesn't change | Dynamic โ€” meaning shifts as edges accumulate | | LLM does classification | LLM does extraction (entities, relations) and discovery | ## Diagnostic Questions Ask these about the system you're designing or reviewing: 1. **What are the success metrics for "the system worked"?** - If: "every input got categorized" โ†’ filing cabinet - If: "the user found a connection they didn't know about" โ†’ graph 2. **Where is `type` (or its synonym) defined?** - If: a Python enum / TypeScript union / database CHECK constraint โ†’ static - If: as nodes in the graph that the user can rename/merge/split โ†’ dynamic 3. **Could you delete the enum and the system still organize content?** - If no: the enum is structural, you're filing - If yes (clusters, tags, graph traversal still work): you're graphing 4. **What does the LLM prompt ask?** - "Pick one of: idea, insight, project, ..." โ†’ classifier - "What is this about? What does it connect to? What entities does it mention?" โ†’ extractor 5. **What happens when the user dumps in 30 unrelated docs?** - 30 notes in 8 folders, neatly sorted โ†’ filing cabinet (test report looks great) - 30 notes + emergent communities + unexpected cross-links surfaced โ†’ graph If 4+ of 5 say "filing cabinet", the system has the trap. ## How To Avoid ### Design-time defenses 1. **Don't make `type` (or `category`, `kind`) a primary field.** Demote it to one of many tags from day one. If you need typed views, derive them from tag queries. 2. **Folder structure should not encode taxonomy.** Use date (`notes/2026-05/`), hash (`notes/ab/cd/`), or single flat directory. Reserve folders for substantive splits (raw vs. compiled, e.g. `seeds/` vs `garden/`). 3. **LLM prompt asks for extraction, not selection.** "What entities are mentioned? What concepts? What does this connect to?" โ€” open-ended. Not "which of these 8 buckets does this go in?" 4. **Build the graph extractor BEFORE the type system.** If you know which entities are in each note and how they relate, "type" is post-hoc analytics, not a primary axis. ### Refactoring an existing trap If you've already shipped a filing cabinet: 1. **Stop new damage first.** Make `type` field optional in writes. New entries can omit it. 2. **Add the graph layer alongside.** Build entity extraction + relation graph in parallel. Don't break the existing folders. 3. **Migrate frontend.** Replace type-coloring with community-coloring. Replace type-filter with tag/entity-filter. 4. **Migrate vault structure.** Move `garden/insights/X.md` โ†’ `garden/notes/YYYY-MM/X.md` with `tags: [..., insight]` preserving the old type as a tag. 5. **Delete the enum.** Only after 1-4 land. Otherwise the dependencies will pull you back. This is multi-PR, multi-week. Plan for it. ## Real-World Cases - **BSage (2026-05)**: 8 hardcoded note_types โ†’ discovered via user pushback after a demo report claimed "32 notes classified successfully across 7 type folders". Users didn't get value because no cross-cluster discovery happened. Refactor delegated to `~/Docs/BSage_Dynamic_Ontology_Refactor.md` (5 phases, ~5 weeks). - **Roam Research's design choice**: zero types, only tags + backlinks + queries. Created the modern thinking on emergent ontology. Notion later added databases/types and is structurally a filing cabinet despite sharing some surface (backlinks) with Roam. ## Cost of Missing This You will: 1. Ship a system that demos well ("look, perfect classification") 2. Get user feedback "I thought this would help me see patterns" 3. Realize you need 5 weeks of architectural refactor to fix the foundational design choice 4. Pay the cost of migrating live user vaults Recognizing the trap during design = days of work. Recognizing it after shipping = weeks plus user disruption. ## Related - Karpathy Wiki philosophy (continuous self-organization, LLM as merger not classifier) - `large-codebase-deprecation-removal` โ€” relevant when refactoring out of the trap
View on GitHub