From 78b72724ed338ade0ec8662826a217745150ec82 Mon Sep 17 00:00:00 2001
From: Yuxiang Lin
Date: Fri, 10 Apr 2026 19:45:02 +0800
Subject: [PATCH 01/11] Add funding information for Patreon
---
.github/FUNDING.yml | 1 +
1 file changed, 1 insertion(+)
create mode 100644 .github/FUNDING.yml
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..cb75fdf
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+patreon: Lum1104
From 098ad791c09ab9c03528229a932d4d9ac177fb85 Mon Sep 17 00:00:00 2001
From: Lum1104
Date: Thu, 9 Apr 2026 22:56:00 +0800
Subject: [PATCH 02/11] docs: add /understand-knowledge design spec for
personal knowledge base plugin
New skill that takes markdown knowledge bases (Obsidian, Logseq, Dendron, Foam,
Karpathy-style, Zettelkasten, plain) and produces interactive knowledge graphs
with typed nodes/edges, auto-format detection, and dashboard visualization.
Co-Authored-By: Claude Opus 4.6 (1M context)
---
.../2026-04-09-understand-knowledge-design.md | 335 ++++++++++++++++++
1 file changed, 335 insertions(+)
create mode 100644 docs/superpowers/specs/2026-04-09-understand-knowledge-design.md
diff --git a/docs/superpowers/specs/2026-04-09-understand-knowledge-design.md b/docs/superpowers/specs/2026-04-09-understand-knowledge-design.md
new file mode 100644
index 0000000..2c63252
--- /dev/null
+++ b/docs/superpowers/specs/2026-04-09-understand-knowledge-design.md
@@ -0,0 +1,335 @@
+# /understand-knowledge — Personal Knowledge Base Plugin Design
+
+## Overview
+
+A new `/understand-knowledge` skill within the existing Understand Anything plugin that takes any folder of markdown notes and produces an interactive knowledge graph visualized in the existing dashboard.
+
+Inspired by Andrej Karpathy's LLM Wiki pattern — where an LLM compiles and maintains a structured wiki from raw sources — this plugin goes further by adding typed relationship discovery and interactive graph visualization that tools like Obsidian and Logseq cannot provide.
+
+### Goals
+
+- Accept any markdown-based knowledge base (Obsidian vault, Logseq graph, Dendron workspace, Foam, Karpathy-style LLM wiki, Zettelkasten, or plain markdown)
+- Auto-detect the format and adapt parsing accordingly
+- Use LLM analysis to discover implicit relationships beyond explicit links
+- Produce a knowledge graph with typed nodes and edges
+- Visualize in the existing dashboard with knowledge-specific layout, sidebar, and reading mode
+
+### Non-Goals
+
+- Real-time sync with the knowledge base tool (Obsidian, Logseq, etc.)
+- Replacing the user's existing PKM tool — this is a visualization/analysis layer on top
+- Supporting non-markdown formats (PDFs, bookmarks) in v1
+
+---
+
+## Schema Extensions
+
+### New Node Types (5)
+
+Added to the existing `NodeType` union (currently 16 types):
+
+```typescript
+export type NodeType =
+ // existing (16)
+ | "file" | "function" | "class" | "module" | "concept"
+ | "config" | "document" | "service" | "table" | "endpoint"
+ | "pipeline" | "schema" | "resource"
+ | "domain" | "flow" | "step"
+ // knowledge (5 new → 21 total)
+ | "article" | "entity" | "topic" | "claim" | "source";
+```
+
+| Type | What it represents | Example |
+|------|-------------------|---------|
+| `article` | A wiki/note page — the primary content unit | "LLM Knowledge Bases.md" |
+| `entity` | A named thing: person, tool, paper, org, project | "Andrej Karpathy", "Obsidian" |
+| `topic` | A thematic cluster grouping related articles | "Personal Knowledge Management" |
+| `claim` | A specific assertion, insight, or takeaway | "RAG loses context at chunk boundaries" |
+| `source` | Raw/reference material that articles are compiled from | A paper URL, a raw PDF reference |
+
+### New Edge Types (6)
+
+Added to the existing `EdgeType` union (currently 29 types):
+
+```typescript
+export type EdgeType =
+ // existing (29)
+ | ...
+ // knowledge (6 new → 35 total)
+ | "cites" | "contradicts" | "builds_on"
+ | "exemplifies" | "categorized_under" | "authored_by";
+```
+
+| Type | Direction | Meaning |
+|------|-----------|---------|
+| `cites` | article → source | References or draws from |
+| `contradicts` | claim → claim | Conflicts or disagrees with |
+| `builds_on` | article → article | Extends, refines, or deepens |
+| `exemplifies` | entity → concept/topic | Is a concrete example of |
+| `categorized_under` | article/entity → topic | Belongs to this theme |
+| `authored_by` | article → entity | Written or created by |
+
+### New Metadata Interface
+
+```typescript
+export interface KnowledgeMeta {
+ format?: "obsidian" | "logseq" | "dendron" | "foam" | "karpathy" | "zettelkasten" | "plain";
+ wikilinks?: string[];
+ backlinks?: string[];
+ frontmatter?: Record;
+ sourceUrl?: string;
+ confidence?: number; // 0-1, for LLM-inferred relationships
+}
+```
+
+Added as an optional field on `GraphNode`:
+
+```typescript
+export interface GraphNode {
+ // ...existing fields
+ knowledgeMeta?: KnowledgeMeta;
+}
+```
+
+### Graph-Level Kind Flag
+
+```typescript
+export interface KnowledgeGraph {
+ version: string;
+ kind: "codebase" | "knowledge"; // NEW
+ project: ProjectMeta;
+ nodes: GraphNode[];
+ edges: GraphEdge[];
+ layers: Layer[];
+ tour: TourStep[];
+}
+```
+
+The `kind` field tells the dashboard which layout, sidebar, and visual styling to use. For backward compatibility, graphs without a `kind` field default to `"codebase"`.
+
+---
+
+## Format Detection & Format Guides
+
+### Auto-Detection Logic
+
+Scans the target directory for signature files/patterns. Priority order (first match wins):
+
+| Priority | Signal | Detected Format |
+|----------|--------|----------------|
+| 1 | `.obsidian/` directory | Obsidian |
+| 2 | `logseq/` + `pages/` directories | Logseq |
+| 3 | `.dendron.yml` or `*.schema.yml` | Dendron |
+| 4 | `.foam/` or `.vscode/foam.json` | Foam |
+| 5 | `raw/` + `wiki/` + `index.md` | Karpathy |
+| 6 | `[[wikilinks]]` + unique ID prefixes in filenames | Zettelkasten |
+| 7 | Fallback | Plain markdown |
+
+### Format Guides
+
+Located at `skills/understand-knowledge/formats/`. Each guide tells the LLM agents how to parse that format:
+
+```
+skills/understand-knowledge/
+ SKILL.md
+ formats/
+ obsidian.md — [[wikilinks]], [[note|alias]], [[note#heading]],
+ #tags, YAML frontmatter, .obsidian/ config,
+ dataview annotations, canvas files
+ logseq.md — block-based outliner, ((block-refs)),
+ journals/YYYY_MM_DD.md, pages/,
+ property:: value syntax, TODO/DONE states
+ dendron.md — dot-delimited hierarchy (a.b.c.md),
+ .schema.yml for structure validation,
+ cross-vault links, refactoring rules
+ foam.md — [[wikilinks]] + link reference definitions
+ at file bottom, .foam/config, placeholder links
+ karpathy.md — raw/ → wiki/ pipeline, index.md master map,
+ log.md append-only record, _meta/ state,
+ LLM-maintained cross-references
+ zettelkasten.md — atomic notes, unique ID prefixes (timestamps),
+ typed semantic links, one idea per note
+ plain.md — standard [markdown](links), folder hierarchy,
+ heading structure, no special conventions
+```
+
+Each format guide covers:
+- How to parse links (wikilinks vs standard vs block refs)
+- Where metadata lives (frontmatter vs inline properties vs block properties)
+- What the folder structure means (journals/ = daily notes, pages/ = permanent notes)
+- What conventions to respect vs what to infer
+
+### Format Guide Authoring Process
+
+Format guides must be research-backed. During implementation, the agent building each format guide must:
+1. Read the official documentation for that format (Obsidian Help, Logseq docs, Dendron wiki, Foam docs, etc.)
+2. Study real-world examples of that format's structure
+3. Write the guide based on verified behavior, not assumptions
+
+---
+
+## Agent Pipeline
+
+```
+knowledge-scanner → format-detector → article-analyzer → relationship-builder → graph-reviewer
+```
+
+### Agent Definitions
+
+| Agent | Input | Output | Model |
+|-------|-------|--------|-------|
+| `knowledge-scanner` | Target directory path | File manifest: all `.md` files with paths, sizes, first 20 lines preview | `inherit` |
+| `format-detector` | File manifest + directory structure | Detected format + format-specific parsing hints | `inherit` |
+| `article-analyzer` | Individual `.md` file + format guide | Per-file nodes (article, entities, claims) + explicit edges (wikilinks, tags) | `inherit` |
+| `relationship-builder` | All per-file results | Cross-file implicit edges (builds_on, contradicts, categorized_under) + topic clustering + layers | `inherit` |
+| `graph-reviewer` | Assembled graph | Validated graph — deduped entities, consistent edge weights, orphan detection | `inherit` |
+
+### Key Differences from Codebase Pipeline
+
+- **No tree-sitter** — markdown parsing is simpler, mostly regex + LLM interpretation
+- **format-detector** replaces framework detection — picks the right format guide
+- **article-analyzer** replaces file-analyzer — extracts knowledge concepts instead of code structure
+- **relationship-builder** is the heavy LLM step — discovers implicit connections across files that explicit links miss
+- **graph-reviewer** stays similar — validates the assembled graph for consistency
+
+### Intermediate Files
+
+Same pattern as codebase analysis:
+
+```
+.understand-anything/intermediate/
+ knowledge-manifest.json — scanner output
+ format-detection.json — detected format + hints
+ article-*.json — per-file analysis
+ relationships.json — cross-file edges
+ knowledge-graph.json — final assembled graph
+```
+
+Intermediate files are cleaned up after graph assembly (same as codebase flow).
+
+### Incremental Mode (`--ingest`)
+
+When the user runs `/understand-knowledge --ingest path/to/new-source.md`:
+
+1. **knowledge-scanner** — runs on just the new file(s)
+2. **format-detector** — skipped (format already known from initial scan)
+3. **article-analyzer** — processes only new/changed files
+4. **relationship-builder** — runs on new nodes against the existing graph, finds connections to what's already there
+5. **graph-reviewer** — validates the merged result
+
+Existing nodes are preserved; only new nodes/edges are added or updated.
+
+---
+
+## Dashboard Changes
+
+All changes are scoped to graphs with `"kind": "knowledge"`.
+
+### Vertical Flow Layout
+
+- Default to top-down vertical layout (like existing domain/business flow view)
+- Topics at top → articles in middle → entities/claims/sources at bottom
+- Reads like a knowledge hierarchy: broad themes flow down into specifics
+- User can still switch to horizontal or force-directed layout via controls
+
+### Knowledge Sidebar
+
+Replaces NodeInfo when a knowledge graph is loaded:
+
+| Selection | Sidebar Shows |
+|-----------|---------------|
+| Nothing selected | ProjectOverview: format detected, total articles/entities/topics/claims/sources |
+| Article node | Title, summary, tags, frontmatter metadata, backlinks list (clickable), outgoing links, related topics |
+| Entity node | Name, type (person/tool/paper/org), articles that mention it, relationships to other entities |
+| Topic node | Description, child articles, child entities, cross-topic connections |
+| Claim node | Assertion text, supporting articles, contradicting claims (if any), confidence score |
+| Source node | Original URL/path, articles that cite it, ingestion date |
+
+### Reading Mode
+
+- Clicking an article node triggers a reading panel that slides up from the bottom (same pattern as current code viewer overlay)
+- Shows the full compiled markdown rendered as HTML
+- Includes a mini backlinks sidebar within the panel
+- Clicking a `[[wikilink]]` or entity reference in the reading panel navigates the graph to that node
+
+### Node Visual Styling
+
+| Node Type | Shape | Color Accent |
+|-----------|-------|-------------|
+| `article` | Rounded rectangle | Warm amber |
+| `entity` | Circle | Soft blue |
+| `topic` | Large rounded rectangle | Muted gold |
+| `claim` | Diamond | Green/red depending on contradictions |
+| `source` | Small square | Gray |
+
+### Edge Visual Styling
+
+| Edge Type | Style |
+|-----------|-------|
+| `cites` | Dashed line |
+| `contradicts` | Red line |
+| `builds_on` | Solid with arrow |
+| `categorized_under` | Thin gray |
+| `authored_by` | Dotted blue |
+| `exemplifies` | Dotted green |
+
+---
+
+## Skill Interface
+
+### Usage
+
+```bash
+# Full scan — first time or rescan
+/understand-knowledge
+
+# Point at a specific directory
+/understand-knowledge path/to/my-notes
+
+# Incremental ingest — add new sources to existing graph
+/understand-knowledge --ingest path/to/new-note.md
+/understand-knowledge --ingest path/to/new-folder/
+```
+
+### Behavior
+
+1. Auto-detects format (Obsidian, Logseq, Karpathy, etc.)
+2. Announces: "Detected Obsidian vault with 342 notes. Scanning..."
+3. Runs the agent pipeline (scanner → detector → analyzer → relationship-builder → reviewer)
+4. Writes `knowledge-graph.json` to `.understand-anything/` with `"kind": "knowledge"`
+5. Auto-triggers `/understand-dashboard` after completion
+
+### File Structure
+
+```
+skills/understand-knowledge/
+ SKILL.md — skill entry point, orchestration logic
+ formats/
+ obsidian.md
+ logseq.md
+ dendron.md
+ foam.md
+ karpathy.md
+ zettelkasten.md
+ plain.md
+```
+
+### Coexistence with `/understand`
+
+- `/understand` produces `"kind": "codebase"` graphs
+- `/understand-knowledge` produces `"kind": "knowledge"` graphs
+- Both write to `.understand-anything/knowledge-graph.json`
+- Running one replaces the other
+- To scope knowledge analysis to a subdirectory (e.g., `docs/` within a code repo), use `/understand-knowledge path/to/docs`
+
+---
+
+## What This Enables That Nothing Else Does
+
+| Existing Tools | Limitation | Our Advantage |
+|---------------|-----------|---------------|
+| Obsidian graph view | Untyped edges — all links look the same | Typed edges: cites, contradicts, builds_on |
+| Logseq graph | Only shows explicit links | LLM discovers implicit relationships |
+| All PKM tools | Single-format only | Cross-format support with auto-detection |
+| Karpathy LLM Wiki | Flat text wiki, no visualization | Interactive graph dashboard with guided tours |
+| None | No knowledge graph tours | Tour mode walks through a knowledge base step by step |
From e58ceb856faef5d3d5aea88c855754e2b3a833a5 Mon Sep 17 00:00:00 2001
From: Lum1104
Date: Thu, 9 Apr 2026 23:06:32 +0800
Subject: [PATCH 03/11] docs: add /understand-knowledge implementation plan (14
tasks)
Detailed step-by-step plan covering core type extensions, schema validation,
dashboard changes (CSS, store, sidebar, reading panel, edge styling, layout),
agent definitions, format guides, and skill definition.
Co-Authored-By: Claude Opus 4.6 (1M context)
---
.../plans/2026-04-09-understand-knowledge.md | 1740 +++++++++++++++++
1 file changed, 1740 insertions(+)
create mode 100644 docs/superpowers/plans/2026-04-09-understand-knowledge.md
diff --git a/docs/superpowers/plans/2026-04-09-understand-knowledge.md b/docs/superpowers/plans/2026-04-09-understand-knowledge.md
new file mode 100644
index 0000000..4c0635f
--- /dev/null
+++ b/docs/superpowers/plans/2026-04-09-understand-knowledge.md
@@ -0,0 +1,1740 @@
+# /understand-knowledge Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Add a `/understand-knowledge` skill that takes any folder of markdown notes (Obsidian, Logseq, Dendron, Foam, Karpathy-style, Zettelkasten, or plain) and produces an interactive knowledge graph with typed nodes, edges, and dashboard visualization.
+
+**Architecture:** Extends the existing schema with 5 knowledge node types and 6 knowledge edge types. A new 5-agent pipeline (knowledge-scanner → format-detector → article-analyzer → relationship-builder → graph-reviewer) processes markdown files. The dashboard renders knowledge graphs with vertical layout, a knowledge-specific sidebar, and a reading mode panel — all driven by a new `kind` field on the root graph object.
+
+**Tech Stack:** TypeScript, Zod (schema validation), React + ReactFlow (dashboard), dagre (layout), TailwindCSS v4, Vitest (testing)
+
+**Spec:** `docs/superpowers/specs/2026-04-09-understand-knowledge-design.md`
+
+---
+
+## File Structure
+
+### Core package changes
+- Modify: `understand-anything-plugin/packages/core/src/types.ts` — add 5 node types, 6 edge types, `KnowledgeMeta` interface, `kind` field
+- Modify: `understand-anything-plugin/packages/core/src/schema.ts` — add new types to Zod schemas, add aliases
+- Modify: `understand-anything-plugin/packages/core/src/types.test.ts` — add tests for new types
+- Test: `understand-anything-plugin/packages/core/src/__tests__/knowledge-schema.test.ts` — validation tests for knowledge-specific schema
+
+### Dashboard changes
+- Modify: `understand-anything-plugin/packages/dashboard/src/store.ts` — add knowledge node types, edge categories, `ViewMode`, node categories
+- Modify: `understand-anything-plugin/packages/dashboard/src/components/CustomNode.tsx` — add colors for 5 new node types
+- Modify: `understand-anything-plugin/packages/dashboard/src/components/NodeInfo.tsx` — add badge colors and edge labels for new types, add knowledge sidebar sections
+- Modify: `understand-anything-plugin/packages/dashboard/src/components/ProjectOverview.tsx` — add knowledge-specific stats
+- Modify: `understand-anything-plugin/packages/dashboard/src/index.css` — add CSS variables for 5 new node colors
+- Modify: `understand-anything-plugin/packages/dashboard/src/App.tsx` — detect `kind` field, set view mode
+- Create: `understand-anything-plugin/packages/dashboard/src/components/KnowledgeInfo.tsx` — knowledge-specific sidebar
+- Create: `understand-anything-plugin/packages/dashboard/src/components/ReadingPanel.tsx` — full article reading overlay
+
+### Skill & agent definitions
+- Create: `understand-anything-plugin/skills/understand-knowledge/SKILL.md` — skill entry point
+- Create: `understand-anything-plugin/skills/understand-knowledge/formats/obsidian.md`
+- Create: `understand-anything-plugin/skills/understand-knowledge/formats/logseq.md`
+- Create: `understand-anything-plugin/skills/understand-knowledge/formats/dendron.md`
+- Create: `understand-anything-plugin/skills/understand-knowledge/formats/foam.md`
+- Create: `understand-anything-plugin/skills/understand-knowledge/formats/karpathy.md`
+- Create: `understand-anything-plugin/skills/understand-knowledge/formats/zettelkasten.md`
+- Create: `understand-anything-plugin/skills/understand-knowledge/formats/plain.md`
+- Create: `understand-anything-plugin/agents/knowledge-scanner.md`
+- Create: `understand-anything-plugin/agents/format-detector.md`
+- Create: `understand-anything-plugin/agents/article-analyzer.md`
+- Create: `understand-anything-plugin/agents/relationship-builder.md`
+
+Existing `graph-reviewer.md` agent is reused for the final validation step.
+
+---
+
+## Task 1: Extend Core Types
+
+**Files:**
+- Modify: `understand-anything-plugin/packages/core/src/types.ts`
+
+- [ ] **Step 1: Add knowledge node types to NodeType union**
+
+In `understand-anything-plugin/packages/core/src/types.ts`, add the 5 knowledge types after the domain types:
+
+```typescript
+// Node types (21 total: 5 code + 8 non-code + 3 domain + 5 knowledge)
+export type NodeType =
+ | "file" | "function" | "class" | "module" | "concept"
+ | "config" | "document" | "service" | "table" | "endpoint"
+ | "pipeline" | "schema" | "resource"
+ | "domain" | "flow" | "step"
+ | "article" | "entity" | "topic" | "claim" | "source";
+```
+
+- [ ] **Step 2: Add knowledge edge types to EdgeType union**
+
+```typescript
+// Edge types (35 total in 8 categories)
+export type EdgeType =
+ | "imports" | "exports" | "contains" | "inherits" | "implements"
+ | "calls" | "subscribes" | "publishes" | "middleware"
+ | "reads_from" | "writes_to" | "transforms" | "validates"
+ | "depends_on" | "tested_by" | "configures"
+ | "related" | "similar_to"
+ | "deploys" | "serves" | "provisions" | "triggers"
+ | "migrates" | "documents" | "routes" | "defines_schema"
+ | "contains_flow" | "flow_step" | "cross_domain"
+ | "cites" | "contradicts" | "builds_on" | "exemplifies" | "categorized_under" | "authored_by";
+```
+
+- [ ] **Step 3: Add KnowledgeMeta interface**
+
+Add after the `DomainMeta` interface:
+
+```typescript
+// Optional knowledge metadata for article/entity/topic/claim/source nodes
+export interface KnowledgeMeta {
+ format?: "obsidian" | "logseq" | "dendron" | "foam" | "karpathy" | "zettelkasten" | "plain";
+ wikilinks?: string[];
+ backlinks?: string[];
+ frontmatter?: Record;
+ sourceUrl?: string;
+ confidence?: number; // 0-1, for LLM-inferred relationships
+}
+```
+
+- [ ] **Step 4: Add knowledgeMeta to GraphNode**
+
+```typescript
+export interface GraphNode {
+ id: string;
+ type: NodeType;
+ name: string;
+ filePath?: string;
+ lineRange?: [number, number];
+ summary: string;
+ tags: string[];
+ complexity: "simple" | "moderate" | "complex";
+ languageNotes?: string;
+ domainMeta?: DomainMeta;
+ knowledgeMeta?: KnowledgeMeta;
+}
+```
+
+- [ ] **Step 5: Add kind field to KnowledgeGraph**
+
+```typescript
+export interface KnowledgeGraph {
+ version: string;
+ kind?: "codebase" | "knowledge"; // undefined defaults to "codebase" for backward compat
+ project: ProjectMeta;
+ nodes: GraphNode[];
+ edges: GraphEdge[];
+ layers: Layer[];
+ tour: TourStep[];
+}
+```
+
+- [ ] **Step 6: Build core and verify no type errors**
+
+Run: `pnpm --filter @understand-anything/core build`
+Expected: Clean build, no errors
+
+- [ ] **Step 7: Commit**
+
+```bash
+git add understand-anything-plugin/packages/core/src/types.ts
+git commit -m "feat(core): add knowledge node types, edge types, KnowledgeMeta, and graph kind field"
+```
+
+---
+
+## Task 2: Extend Schema Validation
+
+**Files:**
+- Modify: `understand-anything-plugin/packages/core/src/schema.ts`
+- Create: `understand-anything-plugin/packages/core/src/__tests__/knowledge-schema.test.ts`
+
+- [ ] **Step 1: Add knowledge edge types to EdgeTypeSchema**
+
+In `understand-anything-plugin/packages/core/src/schema.ts`, update the `EdgeTypeSchema` z.enum to include the 6 new types:
+
+```typescript
+export const EdgeTypeSchema = z.enum([
+ "imports", "exports", "contains", "inherits", "implements",
+ "calls", "subscribes", "publishes", "middleware",
+ "reads_from", "writes_to", "transforms", "validates",
+ "depends_on", "tested_by", "configures",
+ "related", "similar_to",
+ "deploys", "serves", "provisions", "triggers",
+ "migrates", "documents", "routes", "defines_schema",
+ "contains_flow", "flow_step", "cross_domain",
+ // Knowledge
+ "cites", "contradicts", "builds_on", "exemplifies", "categorized_under", "authored_by",
+]);
+```
+
+- [ ] **Step 2: Add knowledge node type aliases**
+
+Add to `NODE_TYPE_ALIASES`:
+
+```typescript
+ // Knowledge aliases
+ note: "article",
+ page: "article",
+ wiki_page: "article",
+ person: "entity",
+ tool: "entity",
+ paper: "entity",
+ organization: "entity",
+ org: "entity",
+ category: "topic",
+ theme: "topic",
+ tag_topic: "topic",
+ assertion: "claim",
+ insight: "claim",
+ takeaway: "claim",
+ reference: "source",
+ raw: "source",
+ citation: "source",
+```
+
+- [ ] **Step 3: Add knowledge edge type aliases**
+
+Add to `EDGE_TYPE_ALIASES`:
+
+```typescript
+ // Knowledge aliases
+ references: "cites",
+ cited_by: "cites",
+ sourced_from: "cites",
+ conflicts_with: "contradicts",
+ disagrees_with: "contradicts",
+ extends: "builds_on", // Note: "extends" was already mapped to "inherits" — knowledge context will use builds_on via the relationship-builder agent prompt, so keep "extends" → "inherits" for code
+ refines: "builds_on",
+ deepens: "builds_on",
+ example_of: "exemplifies",
+ instance_of: "exemplifies",
+ belongs_to: "categorized_under",
+ tagged_with: "categorized_under",
+ part_of: "categorized_under",
+ written_by: "authored_by",
+ created_by: "authored_by",
+```
+
+- [ ] **Step 4: Write the failing test for knowledge graph validation**
+
+Create `understand-anything-plugin/packages/core/src/__tests__/knowledge-schema.test.ts`:
+
+```typescript
+import { describe, it, expect } from "vitest";
+import { validateGraph } from "../schema";
+import type { KnowledgeGraph } from "../types";
+
+describe("knowledge graph schema validation", () => {
+ const minimalKnowledgeGraph: KnowledgeGraph = {
+ version: "1.0",
+ kind: "knowledge",
+ project: {
+ name: "Test KB",
+ languages: [],
+ frameworks: [],
+ description: "A test knowledge base",
+ analyzedAt: new Date().toISOString(),
+ gitCommitHash: "abc123",
+ },
+ nodes: [
+ {
+ id: "article:test-note",
+ type: "article",
+ name: "Test Note",
+ summary: "A test article node",
+ tags: ["test"],
+ complexity: "simple",
+ },
+ {
+ id: "entity:karpathy",
+ type: "entity",
+ name: "Andrej Karpathy",
+ summary: "AI researcher",
+ tags: ["person", "ai"],
+ complexity: "simple",
+ },
+ {
+ id: "topic:pkm",
+ type: "topic",
+ name: "Personal Knowledge Management",
+ summary: "Tools and methods for managing personal knowledge",
+ tags: ["knowledge", "productivity"],
+ complexity: "moderate",
+ },
+ ],
+ edges: [
+ {
+ source: "article:test-note",
+ target: "entity:karpathy",
+ type: "authored_by",
+ direction: "forward",
+ weight: 0.8,
+ },
+ {
+ source: "article:test-note",
+ target: "topic:pkm",
+ type: "categorized_under",
+ direction: "forward",
+ weight: 0.7,
+ },
+ ],
+ layers: [
+ {
+ id: "layer:pkm",
+ name: "PKM",
+ description: "Personal Knowledge Management topic cluster",
+ nodeIds: ["article:test-note", "topic:pkm"],
+ },
+ ],
+ tour: [],
+ };
+
+ it("validates a minimal knowledge graph", () => {
+ const result = validateGraph(minimalKnowledgeGraph);
+ const fatals = result.issues.filter((i) => i.level === "fatal");
+ expect(fatals).toHaveLength(0);
+ });
+
+ it("accepts all knowledge node types", () => {
+ const graph = {
+ ...minimalKnowledgeGraph,
+ nodes: [
+ ...minimalKnowledgeGraph.nodes,
+ { id: "claim:rag-bad", type: "claim", name: "RAG loses context", summary: "An assertion", tags: ["claim"], complexity: "simple" },
+ { id: "source:paper1", type: "source", name: "Attention paper", summary: "A source", tags: ["paper"], complexity: "simple" },
+ ],
+ };
+ const result = validateGraph(graph);
+ const fatals = result.issues.filter((i) => i.level === "fatal");
+ expect(fatals).toHaveLength(0);
+ });
+
+ it("accepts all knowledge edge types", () => {
+ const graph = {
+ ...minimalKnowledgeGraph,
+ nodes: [
+ ...minimalKnowledgeGraph.nodes,
+ { id: "claim:c1", type: "claim", name: "Claim 1", summary: "c1", tags: [], complexity: "simple" },
+ { id: "claim:c2", type: "claim", name: "Claim 2", summary: "c2", tags: [], complexity: "simple" },
+ { id: "source:s1", type: "source", name: "Source 1", summary: "s1", tags: [], complexity: "simple" },
+ { id: "article:a2", type: "article", name: "Article 2", summary: "a2", tags: [], complexity: "simple" },
+ ],
+ edges: [
+ ...minimalKnowledgeGraph.edges,
+ { source: "article:test-note", target: "source:s1", type: "cites", direction: "forward", weight: 0.7 },
+ { source: "claim:c1", target: "claim:c2", type: "contradicts", direction: "forward", weight: 0.6 },
+ { source: "article:a2", target: "article:test-note", type: "builds_on", direction: "forward", weight: 0.7 },
+ { source: "entity:karpathy", target: "topic:pkm", type: "exemplifies", direction: "forward", weight: 0.5 },
+ ],
+ };
+ const result = validateGraph(graph);
+ const fatals = result.issues.filter((i) => i.level === "fatal");
+ expect(fatals).toHaveLength(0);
+ });
+
+ it("resolves knowledge node type aliases", () => {
+ const graph = {
+ ...minimalKnowledgeGraph,
+ nodes: [
+ { id: "note:n1", type: "note", name: "A Note", summary: "note alias", tags: [], complexity: "simple" },
+ { id: "person:p1", type: "person", name: "A Person", summary: "person alias", tags: [], complexity: "simple" },
+ ],
+ edges: [],
+ layers: [],
+ };
+ const result = validateGraph(graph);
+ const noteNode = result.graph.nodes.find((n) => n.id === "note:n1");
+ const personNode = result.graph.nodes.find((n) => n.id === "person:p1");
+ expect(noteNode?.type).toBe("article");
+ expect(personNode?.type).toBe("entity");
+ });
+
+ it("resolves knowledge edge type aliases", () => {
+ const graph = {
+ ...minimalKnowledgeGraph,
+ edges: [
+ { source: "article:test-note", target: "entity:karpathy", type: "written_by", direction: "forward", weight: 0.8 },
+ ],
+ };
+ const result = validateGraph(graph);
+ const edge = result.graph.edges.find((e) => e.source === "article:test-note" && e.target === "entity:karpathy");
+ expect(edge?.type).toBe("authored_by");
+ });
+});
+```
+
+- [ ] **Step 5: Run tests to verify they fail**
+
+Run: `pnpm --filter @understand-anything/core test -- --run src/__tests__/knowledge-schema.test.ts`
+Expected: Tests fail because EdgeTypeSchema doesn't include knowledge types yet (if schema.ts wasn't updated), or pass if Steps 1-3 were done correctly.
+
+- [ ] **Step 6: Run all core tests to verify nothing is broken**
+
+Run: `pnpm --filter @understand-anything/core test -- --run`
+Expected: All existing tests pass, new knowledge tests pass
+
+- [ ] **Step 7: Commit**
+
+```bash
+git add understand-anything-plugin/packages/core/src/schema.ts understand-anything-plugin/packages/core/src/__tests__/knowledge-schema.test.ts
+git commit -m "feat(core): add knowledge types to schema validation with aliases and tests"
+```
+
+---
+
+## Task 3: Dashboard — CSS Variables & Node Colors
+
+**Files:**
+- Modify: `understand-anything-plugin/packages/dashboard/src/index.css`
+
+- [ ] **Step 1: Add CSS variables for 5 knowledge node types**
+
+In `understand-anything-plugin/packages/dashboard/src/index.css`, add after the existing `--color-node-resource` line:
+
+```css
+ /* Knowledge node colors */
+ --color-node-article: #d4a574; /* warm amber */
+ --color-node-entity: #7ba4c9; /* soft blue */
+ --color-node-topic: #c9b06c; /* muted gold */
+ --color-node-claim: #6fb07a; /* soft green */
+ --color-node-source: #8a8a8a; /* gray */
+```
+
+- [ ] **Step 2: Add Tailwind text-color utilities for knowledge nodes**
+
+Verify TailwindCSS v4 picks up the CSS variables automatically. If the existing pattern uses `text-node-*` classes defined elsewhere, add matching entries. Check if there's a Tailwind config or if the CSS variables are consumed directly.
+
+Look at how existing `text-node-file` etc. are defined — if they're in the CSS file as utility classes, add:
+
+```css
+ .text-node-article { color: var(--color-node-article); }
+ .text-node-entity { color: var(--color-node-entity); }
+ .text-node-topic { color: var(--color-node-topic); }
+ .text-node-claim { color: var(--color-node-claim); }
+ .text-node-source { color: var(--color-node-source); }
+```
+
+And corresponding `border-node-*` and `bg-node-*` variants if the pattern requires them.
+
+- [ ] **Step 3: Commit**
+
+```bash
+git add understand-anything-plugin/packages/dashboard/src/index.css
+git commit -m "feat(dashboard): add CSS variables and utility classes for knowledge node types"
+```
+
+---
+
+## Task 4: Dashboard — Store & Type Maps
+
+**Files:**
+- Modify: `understand-anything-plugin/packages/dashboard/src/store.ts`
+
+- [ ] **Step 1: Add knowledge types to NodeType union**
+
+Update the local `NodeType` in store.ts:
+
+```typescript
+export type NodeType = "file" | "function" | "class" | "module" | "concept" | "config" | "document" | "service" | "table" | "endpoint" | "pipeline" | "schema" | "resource" | "domain" | "flow" | "step" | "article" | "entity" | "topic" | "claim" | "source";
+```
+
+- [ ] **Step 2: Add knowledge edge category**
+
+Update `EdgeCategory` and `EDGE_CATEGORY_MAP`:
+
+```typescript
+export type EdgeCategory = "structural" | "behavioral" | "data-flow" | "dependencies" | "semantic" | "infrastructure" | "domain" | "knowledge";
+
+export const EDGE_CATEGORY_MAP: Record = {
+ structural: ["imports", "exports", "contains", "inherits", "implements"],
+ behavioral: ["calls", "subscribes", "publishes", "middleware"],
+ "data-flow": ["reads_from", "writes_to", "transforms", "validates"],
+ dependencies: ["depends_on", "tested_by", "configures"],
+ semantic: ["related", "similar_to"],
+ infrastructure: ["deploys", "serves", "provisions", "triggers"],
+ domain: ["contains_flow", "flow_step", "cross_domain"],
+ knowledge: ["cites", "contradicts", "builds_on", "exemplifies", "categorized_under", "authored_by"],
+};
+```
+
+- [ ] **Step 3: Add knowledge to ALL_NODE_TYPES and ALL_EDGE_CATEGORIES**
+
+```typescript
+export const ALL_NODE_TYPES: NodeType[] = ["file", "function", "class", "module", "concept", "config", "document", "service", "table", "endpoint", "pipeline", "schema", "resource", "domain", "flow", "step", "article", "entity", "topic", "claim", "source"];
+
+export const ALL_EDGE_CATEGORIES: EdgeCategory[] = ["structural", "behavioral", "data-flow", "dependencies", "semantic", "infrastructure", "domain", "knowledge"];
+```
+
+- [ ] **Step 4: Add "knowledge" to ViewMode and NodeCategory**
+
+```typescript
+export type ViewMode = "structural" | "domain" | "knowledge";
+
+export type NodeCategory = "code" | "config" | "docs" | "infra" | "data" | "domain" | "knowledge";
+```
+
+Update the `NODE_CATEGORY_MAP` (find where it maps node types to categories) to include:
+
+```typescript
+ article: "knowledge",
+ entity: "knowledge",
+ topic: "knowledge",
+ claim: "knowledge",
+ source: "knowledge",
+```
+
+- [ ] **Step 5: Add knowledge node type filter default**
+
+In the store's initial state `nodeTypeFilters`, add:
+
+```typescript
+nodeTypeFilters: { code: true, config: true, docs: true, infra: true, data: true, domain: true, knowledge: true },
+```
+
+- [ ] **Step 6: Build dashboard and verify no errors**
+
+Run: `pnpm --filter @understand-anything/dashboard build`
+Expected: Clean build
+
+- [ ] **Step 7: Commit**
+
+```bash
+git add understand-anything-plugin/packages/dashboard/src/store.ts
+git commit -m "feat(dashboard): add knowledge types to store, edge categories, and view mode"
+```
+
+---
+
+## Task 5: Dashboard — CustomNode & NodeInfo Type Maps
+
+**Files:**
+- Modify: `understand-anything-plugin/packages/dashboard/src/components/CustomNode.tsx`
+- Modify: `understand-anything-plugin/packages/dashboard/src/components/NodeInfo.tsx`
+
+- [ ] **Step 1: Add knowledge node colors to CustomNode.tsx**
+
+In `typeColors` map, add after the `step` entry:
+
+```typescript
+ // Knowledge
+ article: "var(--color-node-article)",
+ entity: "var(--color-node-entity)",
+ topic: "var(--color-node-topic)",
+ claim: "var(--color-node-claim)",
+ source: "var(--color-node-source)",
+```
+
+In `typeTextColors` map, add:
+
+```typescript
+ // Knowledge
+ article: "text-node-article",
+ entity: "text-node-entity",
+ topic: "text-node-topic",
+ claim: "text-node-claim",
+ source: "text-node-source",
+```
+
+- [ ] **Step 2: Add knowledge node badge colors to NodeInfo.tsx**
+
+In `typeBadgeColors` map, add:
+
+```typescript
+ // Knowledge
+ article: "text-node-article border border-node-article/30 bg-node-article/10",
+ entity: "text-node-entity border border-node-entity/30 bg-node-entity/10",
+ topic: "text-node-topic border border-node-topic/30 bg-node-topic/10",
+ claim: "text-node-claim border border-node-claim/30 bg-node-claim/10",
+ source: "text-node-source border border-node-source/30 bg-node-source/10",
+```
+
+- [ ] **Step 3: Add knowledge edge labels to NodeInfo.tsx**
+
+In `EDGE_LABELS` map, add:
+
+```typescript
+ // Knowledge
+ cites: { forward: "cites", backward: "cited by" },
+ contradicts: { forward: "contradicts", backward: "contradicted by" },
+ builds_on: { forward: "builds on", backward: "built upon by" },
+ exemplifies: { forward: "exemplifies", backward: "exemplified by" },
+ categorized_under: { forward: "categorized under", backward: "categorizes" },
+ authored_by: { forward: "authored by", backward: "authored" },
+```
+
+- [ ] **Step 4: Build dashboard and verify**
+
+Run: `pnpm --filter @understand-anything/dashboard build`
+Expected: Clean build, no type errors
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add understand-anything-plugin/packages/dashboard/src/components/CustomNode.tsx understand-anything-plugin/packages/dashboard/src/components/NodeInfo.tsx
+git commit -m "feat(dashboard): add knowledge node colors, badge colors, and edge labels"
+```
+
+---
+
+## Task 6: Dashboard — Knowledge Sidebar Component
+
+**Files:**
+- Create: `understand-anything-plugin/packages/dashboard/src/components/KnowledgeInfo.tsx`
+- Modify: `understand-anything-plugin/packages/dashboard/src/App.tsx`
+
+- [ ] **Step 1: Create KnowledgeInfo.tsx**
+
+Create `understand-anything-plugin/packages/dashboard/src/components/KnowledgeInfo.tsx`:
+
+```tsx
+import { useDashboardStore } from "../store";
+import type { GraphNode, GraphEdge, KnowledgeGraph } from "@understand-anything/core/types";
+
+const KNOWLEDGE_NODE_TYPES = new Set(["article", "entity", "topic", "claim", "source"]);
+
+function getBacklinks(nodeId: string, edges: GraphEdge[]): string[] {
+ return edges
+ .filter((e) => e.target === nodeId)
+ .map((e) => e.source);
+}
+
+function getOutgoingLinks(nodeId: string, edges: GraphEdge[]): string[] {
+ return edges
+ .filter((e) => e.source === nodeId)
+ .map((e) => e.target);
+}
+
+function NodeLink({ nodeId, nodes, onNavigate }: { nodeId: string; nodes: GraphNode[]; onNavigate: (id: string) => void }) {
+ const node = nodes.find((n) => n.id === nodeId);
+ if (!node) return {nodeId};
+ return (
+
+ );
+}
+
+export default function KnowledgeInfo() {
+ const graph = useDashboardStore((s) => s.graph);
+ const selectedNode = useDashboardStore((s) => s.selectedNode);
+ const setSelectedNode = useDashboardStore((s) => s.setSelectedNode);
+
+ if (!graph || !selectedNode) return null;
+
+ const node = graph.nodes.find((n) => n.id === selectedNode);
+ if (!node) return null;
+
+ const backlinks = getBacklinks(node.id, graph.edges);
+ const outgoing = getOutgoingLinks(node.id, graph.edges);
+ const meta = node.knowledgeMeta;
+
+ return (
+
+ {/* Header */}
+
+
{node.type}
+
{node.name}
+
+
+ {/* Summary */}
+
{node.summary}
+
+ {/* Tags */}
+ {node.tags.length > 0 && (
+
+ {node.tags.map((tag) => (
+
+ {tag}
+
+ ))}
+
+ )}
+
+ {/* Knowledge-specific metadata */}
+ {meta?.sourceUrl && (
+
+
Source
+
{meta.sourceUrl}
+
+ )}
+
+ {meta?.confidence !== undefined && (
+
+
Confidence
+
+
+
{Math.round(meta.confidence * 100)}%
+
+
+ )}
+
+ {/* Frontmatter */}
+ {meta?.frontmatter && Object.keys(meta.frontmatter).length > 0 && (
+
+
Frontmatter
+
+ {Object.entries(meta.frontmatter).map(([key, value]) => (
+
+ {key}:{" "}
+ {String(value)}
+
+ ))}
+
+
+ )}
+
+ {/* Backlinks */}
+ {backlinks.length > 0 && (
+
+
+ Backlinks ({backlinks.length})
+
+
+ {backlinks.map((id) => (
+
+ ))}
+
+
+ )}
+
+ {/* Outgoing */}
+ {outgoing.length > 0 && (
+
+
+ Outgoing Links ({outgoing.length})
+
+
+ {outgoing.map((id) => (
+
+ ))}
+
+
+ )}
+
+ );
+}
+```
+
+- [ ] **Step 2: Integrate KnowledgeInfo into App.tsx sidebar rendering**
+
+In `understand-anything-plugin/packages/dashboard/src/App.tsx`, find where the sidebar renders `NodeInfo` and add a condition: if `graph.kind === "knowledge"` and a node is selected, render `KnowledgeInfo` instead of `NodeInfo`.
+
+Import at top:
+```typescript
+import KnowledgeInfo from "./components/KnowledgeInfo";
+```
+
+In the sidebar section, wrap the existing NodeInfo render:
+```tsx
+{graph?.kind === "knowledge" ? : }
+```
+
+- [ ] **Step 3: Build dashboard and verify**
+
+Run: `pnpm --filter @understand-anything/dashboard build`
+Expected: Clean build
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add understand-anything-plugin/packages/dashboard/src/components/KnowledgeInfo.tsx understand-anything-plugin/packages/dashboard/src/App.tsx
+git commit -m "feat(dashboard): add KnowledgeInfo sidebar component for knowledge graphs"
+```
+
+---
+
+## Task 7: Dashboard — Reading Panel
+
+**Files:**
+- Create: `understand-anything-plugin/packages/dashboard/src/components/ReadingPanel.tsx`
+- Modify: `understand-anything-plugin/packages/dashboard/src/App.tsx`
+
+- [ ] **Step 1: Create ReadingPanel.tsx**
+
+Create `understand-anything-plugin/packages/dashboard/src/components/ReadingPanel.tsx`:
+
+```tsx
+import { useState } from "react";
+import { useDashboardStore } from "../store";
+
+export default function ReadingPanel() {
+ const graph = useDashboardStore((s) => s.graph);
+ const selectedNode = useDashboardStore((s) => s.selectedNode);
+ const setSelectedNode = useDashboardStore((s) => s.setSelectedNode);
+ const [isExpanded, setIsExpanded] = useState(false);
+
+ if (!graph || graph.kind !== "knowledge" || !selectedNode) return null;
+
+ const node = graph.nodes.find((n) => n.id === selectedNode);
+ if (!node || node.type !== "article") return null;
+
+ // Get backlinks for this article
+ const backlinks = graph.edges
+ .filter((e) => e.target === node.id)
+ .map((e) => {
+ const sourceNode = graph.nodes.find((n) => n.id === e.source);
+ return sourceNode ? { id: sourceNode.id, name: sourceNode.name, type: sourceNode.type } : null;
+ })
+ .filter(Boolean) as { id: string; name: string; type: string }[];
+
+ return (
+
+ {/* Header bar */}
+
+
+ Reading
+ {node.name}
+
+
+
+
+
+
+
+
+ {/* Main content */}
+
+
+
{node.name}
+
+ {/* Tags */}
+ {node.tags.length > 0 && (
+
+ {node.tags.map((tag) => (
+
+ {tag}
+
+ ))}
+
+ )}
+
+ {/* Article content (summary for now — full markdown rendering is a future enhancement) */}
+
+
+ {/* Frontmatter metadata */}
+ {node.knowledgeMeta?.frontmatter && Object.keys(node.knowledgeMeta.frontmatter).length > 0 && (
+
+
Metadata
+ {Object.entries(node.knowledgeMeta.frontmatter).map(([key, value]) => (
+
+ {key}:{" "}
+ {String(value)}
+
+ ))}
+
+ )}
+
+
+
+ {/* Backlinks sidebar */}
+ {backlinks.length > 0 && (
+
+
+ Backlinks ({backlinks.length})
+
+
+ {backlinks.map((link) => (
+
+ ))}
+
+
+ )}
+
+
+ );
+}
+```
+
+- [ ] **Step 2: Add ReadingPanel to App.tsx**
+
+Import and render `ReadingPanel` in the main dashboard layout, positioned at the bottom:
+
+```typescript
+import ReadingPanel from "./components/ReadingPanel";
+```
+
+Add `` inside the dashboard container, after the graph view area.
+
+- [ ] **Step 3: Build and verify**
+
+Run: `pnpm --filter @understand-anything/dashboard build`
+Expected: Clean build
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add understand-anything-plugin/packages/dashboard/src/components/ReadingPanel.tsx understand-anything-plugin/packages/dashboard/src/App.tsx
+git commit -m "feat(dashboard): add ReadingPanel for article reading mode in knowledge graphs"
+```
+
+---
+
+## Task 8: Dashboard — Vertical Layout for Knowledge Graphs
+
+**Files:**
+- Modify: `understand-anything-plugin/packages/dashboard/src/components/GraphView.tsx`
+- Modify: `understand-anything-plugin/packages/dashboard/src/utils/layout.ts` (if direction isn't already configurable)
+
+- [ ] **Step 1: Check how layout direction is passed to dagre**
+
+Read `GraphView.tsx` to find where `applyDagreLayout` is called. The layout.ts `applyDagreLayout` already accepts a `direction: "TB" | "LR"` parameter (default `"TB"`).
+
+Find where GraphView calls this function and check what direction it passes.
+
+- [ ] **Step 2: Pass graph kind to layout decision**
+
+In `GraphView.tsx`, where the layout is applied, check the graph's `kind` field. If `kind === "knowledge"`, use `"TB"` (top-to-bottom). If `kind === "codebase"` or undefined, keep the existing default.
+
+The graph object is available via the store. Add:
+
+```typescript
+const graphKind = useDashboardStore((s) => s.graph?.kind);
+const layoutDirection = graphKind === "knowledge" ? "TB" : "LR";
+```
+
+Pass `layoutDirection` to the layout call.
+
+- [ ] **Step 3: Build and verify**
+
+Run: `pnpm --filter @understand-anything/dashboard build`
+Expected: Clean build
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add understand-anything-plugin/packages/dashboard/src/components/GraphView.tsx
+git commit -m "feat(dashboard): use vertical top-down layout for knowledge graphs"
+```
+
+---
+
+## Task 9: Dashboard — Knowledge Edge Styling
+
+**Files:**
+- Modify: `understand-anything-plugin/packages/dashboard/src/components/GraphView.tsx`
+
+- [ ] **Step 1: Add knowledge edge style map**
+
+In `GraphView.tsx`, add a style map for knowledge edge types. Follow the existing pattern from `DomainGraphView.tsx` which uses ReactFlow's `style` prop:
+
+```typescript
+const KNOWLEDGE_EDGE_STYLES: Record = {
+ cites: { strokeDasharray: "6 3", strokeWidth: 1.5 },
+ contradicts: { stroke: "#c97070", strokeWidth: 2 },
+ builds_on: { stroke: "var(--color-accent)", strokeWidth: 2 },
+ categorized_under: { stroke: "rgba(150,150,150,0.5)", strokeWidth: 1 },
+ authored_by: { strokeDasharray: "3 3", stroke: "var(--color-node-entity)", strokeWidth: 1.5 },
+ exemplifies: { strokeDasharray: "3 3", stroke: "var(--color-node-claim)", strokeWidth: 1.5 },
+};
+```
+
+- [ ] **Step 2: Apply styles when building ReactFlow edges**
+
+Where edges are converted to ReactFlow format, check if the graph is `kind === "knowledge"` and the edge type has a knowledge style. Merge the style:
+
+```typescript
+const knowledgeStyle = graph?.kind === "knowledge" ? KNOWLEDGE_EDGE_STYLES[edge.type] : undefined;
+// Merge with existing edge style
+const style = { ...baseEdgeStyle, ...knowledgeStyle };
+```
+
+- [ ] **Step 3: Build and verify**
+
+Run: `pnpm --filter @understand-anything/dashboard build`
+Expected: Clean build
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add understand-anything-plugin/packages/dashboard/src/components/GraphView.tsx
+git commit -m "feat(dashboard): add distinct edge styles for knowledge relationship types"
+```
+
+---
+
+## Task 10: Dashboard — Knowledge-Aware ProjectOverview
+
+**Files:**
+- Modify: `understand-anything-plugin/packages/dashboard/src/components/ProjectOverview.tsx`
+
+- [ ] **Step 1: Add knowledge-specific stats**
+
+In `ProjectOverview.tsx`, detect `graph.kind === "knowledge"` and show knowledge-specific stats:
+
+- Total articles, entities, topics, claims, sources (instead of "code, config, docs, infra, data")
+- Detected format (from the first node's `knowledgeMeta.format`)
+- Remove "Languages" and "Frameworks" sections for knowledge graphs (they'll be empty)
+
+Add after the existing stats grid:
+
+```tsx
+{graph.kind === "knowledge" && (
+
+
Knowledge Stats
+
+ n.type === "article").length} />
+ n.type === "entity").length} />
+ n.type === "topic").length} />
+ n.type === "claim").length} />
+ n.type === "source").length} />
+
+
+)}
+```
+
+Reuse or create a `StatBox` component matching the existing style.
+
+- [ ] **Step 2: Conditionally hide code-specific sections**
+
+Wrap the "Languages", "Frameworks", and code-specific file type breakdown sections in a condition:
+
+```tsx
+{graph.kind !== "knowledge" && (
+ <>
+ {/* existing languages/frameworks/file-types sections */}
+ >
+)}
+```
+
+- [ ] **Step 3: Build and verify**
+
+Run: `pnpm --filter @understand-anything/dashboard build`
+Expected: Clean build
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add understand-anything-plugin/packages/dashboard/src/components/ProjectOverview.tsx
+git commit -m "feat(dashboard): add knowledge-specific stats to ProjectOverview"
+```
+
+---
+
+## Task 11: Create Agent Definitions
+
+**Files:**
+- Create: `understand-anything-plugin/agents/knowledge-scanner.md`
+- Create: `understand-anything-plugin/agents/format-detector.md`
+- Create: `understand-anything-plugin/agents/article-analyzer.md`
+- Create: `understand-anything-plugin/agents/relationship-builder.md`
+
+- [ ] **Step 1: Create knowledge-scanner agent**
+
+Create `understand-anything-plugin/agents/knowledge-scanner.md`:
+
+```markdown
+---
+name: knowledge-scanner
+description: Scans a directory for markdown files and produces a file manifest for knowledge base analysis
+model: inherit
+---
+
+# Knowledge Scanner Agent
+
+You scan a target directory to discover all markdown files for knowledge base analysis.
+
+## Input
+
+You receive a JSON block with:
+- `targetDir` — absolute path to the knowledge base directory
+
+## Task
+
+1. Use Glob/Bash to find all `.md` files in the target directory (recursive)
+2. Exclude common non-content directories: `.obsidian/`, `logseq/`, `.foam/`, `_meta/`, `node_modules/`, `.git/`
+3. For each file, capture:
+ - `path` — relative path from targetDir
+ - `sizeLines` — number of lines
+ - `preview` — first 20 lines of content
+4. Detect directory structure signatures:
+ - Check for `.obsidian/` directory
+ - Check for `logseq/` + `pages/` directories
+ - Check for `.dendron.yml` or `*.schema.yml`
+ - Check for `.foam/` or `.vscode/foam.json`
+ - Check for `raw/` + `wiki/` + `index.md`
+ - Scan a sample of files for `[[wikilinks]]` and unique ID prefixes
+5. Write results to `$PROJECT_ROOT/.understand-anything/intermediate/knowledge-manifest.json`
+
+## Output Schema
+
+```json
+{
+ "targetDir": "/absolute/path",
+ "totalFiles": 342,
+ "directorySignatures": {
+ "hasObsidianDir": true,
+ "hasLogseqDir": false,
+ "hasDendronConfig": false,
+ "hasFoamConfig": false,
+ "hasKarpathyStructure": false,
+ "hasWikilinks": true,
+ "hasUniqueIdPrefixes": false
+ },
+ "files": [
+ {
+ "path": "notes/topic.md",
+ "sizeLines": 45,
+ "preview": "---\ntags: [ai, ml]\n---\n# Topic Name\n..."
+ }
+ ]
+}
+```
+
+## Rules
+
+- Do NOT read file contents beyond the 20-line preview
+- Sort files by path alphabetically
+- Report total count prominently
+- Write output to `.understand-anything/intermediate/knowledge-manifest.json`
+```
+
+- [ ] **Step 2: Create format-detector agent**
+
+Create `understand-anything-plugin/agents/format-detector.md`:
+
+```markdown
+---
+name: format-detector
+description: Detects the knowledge base format from directory signatures and file samples
+model: inherit
+---
+
+# Format Detector Agent
+
+You analyze the knowledge-manifest.json to determine which knowledge base format is being used.
+
+## Input
+
+Read `.understand-anything/intermediate/knowledge-manifest.json` produced by the knowledge-scanner.
+
+## Detection Priority
+
+Apply these rules in order (first match wins):
+
+| Priority | Signal | Format |
+|----------|--------|--------|
+| 1 | `hasObsidianDir === true` | `obsidian` |
+| 2 | `hasLogseqDir === true` | `logseq` |
+| 3 | `hasDendronConfig === true` | `dendron` |
+| 4 | `hasFoamConfig === true` | `foam` |
+| 5 | `hasKarpathyStructure === true` | `karpathy` |
+| 6 | `hasWikilinks === true` AND `hasUniqueIdPrefixes === true` | `zettelkasten` |
+| 7 | fallback | `plain` |
+
+## Output
+
+Write to `.understand-anything/intermediate/format-detection.json`:
+
+```json
+{
+ "format": "obsidian",
+ "confidence": 0.95,
+ "parsingHints": {
+ "linkStyle": "wikilink",
+ "metadataLocation": "yaml-frontmatter",
+ "folderSemantics": "none",
+ "specialFiles": [".obsidian/app.json"],
+ "tagSyntax": "hashtag-inline"
+ }
+}
+```
+
+## Rules
+
+- Always produce exactly one format
+- Set confidence based on how many signals matched
+- Include parsing hints that will help the article-analyzer
+```
+
+- [ ] **Step 3: Create article-analyzer agent**
+
+Create `understand-anything-plugin/agents/article-analyzer.md`:
+
+```markdown
+---
+name: article-analyzer
+description: Analyzes individual markdown files to extract knowledge nodes and explicit edges
+model: inherit
+---
+
+# Article Analyzer Agent
+
+You analyze batches of markdown files from a knowledge base to extract structured knowledge graph data.
+
+## Input
+
+You receive a JSON block with:
+- `projectRoot` — absolute path to the knowledge base
+- `batchFiles` — array of file objects from the manifest (path, sizeLines, preview)
+- `format` — detected format from format-detection.json
+- `parsingHints` — format-specific parsing guidance
+
+You also receive a **format guide** (injected by the skill) that describes how to parse this specific format.
+
+## Task
+
+For each file in the batch:
+
+### 1. Read the full file content
+
+### 2. Extract the article node
+
+- **id**: `article:` (e.g., `article:notes/topic`)
+- **type**: `article`
+- **name**: First heading, or frontmatter title, or filename
+- **filePath**: relative path
+- **summary**: 2-3 sentence summary of the article content
+- **tags**: from frontmatter tags, inline #tags, or inferred from content (3-5 tags)
+- **complexity**: `simple` (<50 lines), `moderate` (50-200 lines), `complex` (>200 lines)
+- **knowledgeMeta**: `{ format, wikilinks, frontmatter }`
+
+### 3. Extract entity nodes
+
+Identify named entities mentioned in the article:
+- People, organizations, tools, papers, projects, datasets
+- **id**: `entity:` (e.g., `entity:andrej-karpathy`)
+- **type**: `entity`
+- **summary**: one-sentence description based on context in the article
+- **tags**: entity category tags like `person`, `tool`, `paper`, `organization`
+
+### 4. Extract claim nodes (for articles with strong assertions)
+
+- Only extract claims that are significant takeaways or insights
+- **id**: `claim::` (e.g., `claim:notes/topic:rag-loses-context`)
+- **type**: `claim`
+- **summary**: the assertion itself
+
+### 5. Extract source nodes (for cited references)
+
+- External URLs, paper references, book citations
+- **id**: `source:`
+- **type**: `source`
+- **knowledgeMeta**: `{ sourceUrl }`
+
+### 6. Extract explicit edges
+
+- `[[wikilinks]]` → find target article, create `related` edge
+- Frontmatter references → `categorized_under` or `related` edges
+- Inline citations/URLs → `cites` edges to source nodes
+- Author mentions → `authored_by` edges
+
+## Node ID Conventions
+
+```
+article:
+entity:
+topic:
+claim::
+source:
+```
+
+Normalize: lowercase, replace spaces with hyphens, remove special characters.
+
+**Deduplicate entities**: If the same entity appears across multiple files in the batch, emit it only once. Use the most informative summary.
+
+## Edge Weight Conventions
+
+```
+contains: 1.0
+authored_by: 0.9
+cites: 0.8
+categorized_under: 0.7
+builds_on: 0.7
+related: 0.5
+exemplifies: 0.5
+contradicts: 0.6
+```
+
+## Output
+
+Write per-batch results to `.understand-anything/intermediate/article-batch-.json`:
+
+```json
+{
+ "nodes": [...],
+ "edges": [...]
+}
+```
+
+## Rules
+
+- One article node per file (always)
+- Entity nodes only for clearly named entities (not generic concepts)
+- Claim nodes only for significant assertions (not every sentence)
+- Source nodes only for explicit external references
+- Deduplicate entities within the batch
+- Respect the format guide for parsing links and metadata
+```
+
+- [ ] **Step 4: Create relationship-builder agent**
+
+Create `understand-anything-plugin/agents/relationship-builder.md`:
+
+```markdown
+---
+name: relationship-builder
+description: Discovers implicit cross-file relationships and builds topic clusters from analyzed knowledge nodes
+model: inherit
+---
+
+# Relationship Builder Agent
+
+You analyze all extracted nodes and edges to discover implicit relationships that explicit links missed.
+
+## Input
+
+Read all `article-batch-*.json` files from `.understand-anything/intermediate/`. Merge all nodes and edges.
+
+## Task
+
+### 1. Deduplicate entities globally
+
+Multiple batches may have emitted the same entity. Merge them:
+- Keep the most detailed summary
+- Union all tags
+- Collapse duplicate IDs
+
+### 2. Discover implicit relationships
+
+For each pair of articles/entities, determine if there's an implicit relationship:
+
+- **builds_on**: Article A extends or deepens ideas from Article B (similar topics, references same entities, but goes further)
+- **contradicts**: Article A makes claims that conflict with Article B
+- **categorized_under**: Group articles into topic clusters
+- **exemplifies**: An entity is a concrete example of a concept/topic
+- **related**: Articles share significant thematic overlap but aren't explicitly linked
+
+Set `confidence` in knowledgeMeta for LLM-inferred edges (0.0-1.0).
+
+### 3. Build topic nodes
+
+Identify thematic clusters across all articles:
+- **id**: `topic:`
+- **type**: `topic`
+- **summary**: description of what this topic covers
+- Create `categorized_under` edges from articles/entities to their topics
+
+### 4. Build layers
+
+Group nodes into layers by topic:
+- Each topic becomes a layer
+- Articles, entities, claims, and sources are assigned to their primary topic's layer
+- Nodes not clearly belonging to any topic go into an "Uncategorized" layer
+
+### 5. Build tour
+
+Create a guided tour through the knowledge base:
+- Start with the broadest topic overview
+- Walk through key articles in a logical learning order
+- Each step covers 1-3 related nodes
+- 5-10 tour steps total
+
+## Output
+
+Write to `.understand-anything/intermediate/relationships.json`:
+
+```json
+{
+ "nodes": [...],
+ "edges": [...],
+ "layers": [...],
+ "tour": [...]
+}
+```
+
+## Rules
+
+- Only add edges with confidence > 0.4
+- Don't duplicate edges that already exist from article-analyzer
+- Topics should be meaningful clusters (3+ articles), not one-off categories
+- Tour should be navigable by someone new to the knowledge base
+- Keep layers balanced — no layer with 50%+ of all nodes
+```
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add understand-anything-plugin/agents/knowledge-scanner.md understand-anything-plugin/agents/format-detector.md understand-anything-plugin/agents/article-analyzer.md understand-anything-plugin/agents/relationship-builder.md
+git commit -m "feat(agents): add knowledge-scanner, format-detector, article-analyzer, and relationship-builder agents"
+```
+
+---
+
+## Task 12: Create Format Guides
+
+**Files:**
+- Create: `understand-anything-plugin/skills/understand-knowledge/formats/obsidian.md`
+- Create: `understand-anything-plugin/skills/understand-knowledge/formats/logseq.md`
+- Create: `understand-anything-plugin/skills/understand-knowledge/formats/dendron.md`
+- Create: `understand-anything-plugin/skills/understand-knowledge/formats/foam.md`
+- Create: `understand-anything-plugin/skills/understand-knowledge/formats/karpathy.md`
+- Create: `understand-anything-plugin/skills/understand-knowledge/formats/zettelkasten.md`
+- Create: `understand-anything-plugin/skills/understand-knowledge/formats/plain.md`
+
+**IMPORTANT**: Each format guide must be **research-backed**. The implementing agent MUST:
+1. Use WebSearch and WebFetch to read the **official documentation** for each format
+2. Study the actual parsing rules, not assumptions
+3. Include specific syntax examples from real documentation
+
+- [ ] **Step 1: Create obsidian.md format guide**
+
+Research Obsidian's official docs (https://help.obsidian.md/) and create `understand-anything-plugin/skills/understand-knowledge/formats/obsidian.md`:
+
+The guide must cover:
+- Detection: `.obsidian/` directory exists
+- Link syntax: `[[wikilink]]`, `[[note|alias]]`, `[[note#heading]]`, `![[embed]]`
+- Metadata: YAML frontmatter between `---` delimiters
+- Tags: `#tag` inline, `tags:` in frontmatter (both array and space-separated)
+- Properties: Obsidian Properties (frontmatter fields rendered in UI)
+- Folder semantics: Obsidian doesn't assign folder meaning by default
+- Special files: `.obsidian/app.json`, `.obsidian/workspace.json` (ignore these)
+- Canvas: `.canvas` files (JSON format, describe spatial layouts — extract card references)
+- Dataview: inline fields `key:: value`, `[key:: value]`
+
+- [ ] **Step 2: Create logseq.md format guide**
+
+Research Logseq docs (https://docs.logseq.com/) and create `understand-anything-plugin/skills/understand-knowledge/formats/logseq.md`:
+
+Cover:
+- Detection: `logseq/` + `pages/` directories
+- Structure: `journals/YYYY_MM_DD.md` (daily notes), `pages/*.md` (named pages)
+- Link syntax: `[[wikilinks]]`, `((block-references))` by UUID
+- Block-based: Content is organized as bullet-point outlines
+- Properties: `key:: value` syntax on blocks
+- Tags: `#tag` inline, page tags via properties
+- Special: `logseq/config.edn` for configuration
+
+- [ ] **Step 3: Create dendron.md format guide**
+
+Research Dendron wiki (https://wiki.dendron.so/) and create `understand-anything-plugin/skills/understand-knowledge/formats/dendron.md`:
+
+Cover:
+- Detection: `.dendron.yml` or `*.schema.yml` files
+- Hierarchy: dot-delimited filenames (`a.b.c.md`)
+- Link syntax: `[[wikilinks]]` with hierarchy awareness
+- Schemas: `.schema.yml` files define expected hierarchy structure
+- Frontmatter: YAML with required `id` and `title` fields
+- Stubs: auto-created intermediate hierarchy files
+
+- [ ] **Step 4: Create foam.md format guide**
+
+Research Foam docs (https://foambubble.github.io/foam/) and create `understand-anything-plugin/skills/understand-knowledge/formats/foam.md`:
+
+Cover:
+- Detection: `.foam/` directory or `.vscode/foam.json`
+- Link syntax: `[[wikilinks]]` plus link reference definitions at file bottom
+- Placeholder links: links to non-existent files
+- Frontmatter: standard YAML
+- Auto-linking: Foam auto-updates links on file rename/move
+
+- [ ] **Step 5: Create karpathy.md format guide**
+
+Research Karpathy's gist (https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) and create `understand-anything-plugin/skills/understand-knowledge/formats/karpathy.md`:
+
+Cover:
+- Detection: `raw/` + `wiki/` directories + `index.md`
+- Structure: `raw/` (immutable sources), `wiki/` (compiled articles), `_meta/` (state)
+- Special files: `index.md` (master page list), `log.md` (append-only operations log)
+- Link style: standard markdown links (not wikilinks)
+- Log parsing: `## [YYYY-MM-DD] operation | Title` entries
+- Wiki articles: LLM-compiled, may have cross-references and backlinks
+
+- [ ] **Step 6: Create zettelkasten.md format guide**
+
+Research zettelkasten.de and create `understand-anything-plugin/skills/understand-knowledge/formats/zettelkasten.md`:
+
+Cover:
+- Detection: `[[wikilinks]]` + unique ID prefixes in filenames (timestamps like `202604091234`)
+- Atomic notes: one idea per note
+- Unique IDs: timestamp or alphanumeric prefix in filename
+- Links: `[[wikilinks]]` with optional typed links
+- Frontmatter: YAML with tags, creation date
+- No folder hierarchy: flat structure, connections via links only
+
+- [ ] **Step 7: Create plain.md format guide**
+
+Create `understand-anything-plugin/skills/understand-knowledge/formats/plain.md`:
+
+Cover:
+- Detection: fallback when no other format detected
+- Links: standard markdown `[text](relative/path.md)` links
+- Structure: folder hierarchy provides categorization
+- Headings: `#` hierarchy provides structure within files
+- No special metadata expectations
+- Tags: none expected (LLM infers topics)
+
+- [ ] **Step 8: Commit**
+
+```bash
+git add understand-anything-plugin/skills/understand-knowledge/formats/
+git commit -m "feat(skill): add 7 research-backed format guides for knowledge base parsing"
+```
+
+---
+
+## Task 13: Create SKILL.md
+
+**Files:**
+- Create: `understand-anything-plugin/skills/understand-knowledge/SKILL.md`
+
+- [ ] **Step 1: Create the skill definition**
+
+Create `understand-anything-plugin/skills/understand-knowledge/SKILL.md`:
+
+```markdown
+---
+name: understand-knowledge
+description: Analyze a markdown knowledge base (Obsidian, Logseq, Dendron, Foam, Karpathy-style, Zettelkasten, or plain) to produce an interactive knowledge graph with typed relationships
+argument-hint: [path/to/notes] [--ingest ]
+---
+
+# /understand-knowledge
+
+Analyze a personal knowledge base of markdown files and produce an interactive knowledge graph.
+
+## Arguments
+
+- `path/to/notes` — (optional) directory containing markdown files. Defaults to current working directory.
+- `--ingest ` — (optional) incrementally add new file(s) to an existing knowledge graph.
+
+## Phase 0: Pre-flight
+
+1. Determine the target directory:
+ - If a path argument is provided, use it
+ - Otherwise use the current working directory
+2. Create `.understand-anything/` and `.understand-anything/intermediate/` directories if they don't exist
+3. If `--ingest` flag is present:
+ - Verify `.understand-anything/knowledge-graph.json` exists (error if not — must run full scan first)
+ - Read the existing graph
+ - Skip to Phase 2 with only the new/changed files
+4. Get the current git commit hash (if in a git repo, otherwise use "no-git")
+
+## Phase 1: SCAN
+
+Dispatch the **knowledge-scanner** agent:
+
+```json
+{
+ "targetDir": ""
+}
+```
+
+Wait for the agent to write `.understand-anything/intermediate/knowledge-manifest.json`.
+
+Report: "Scanned {totalFiles} markdown files."
+
+## Phase 2: FORMAT DETECTION
+
+Dispatch the **format-detector** agent.
+
+Wait for `.understand-anything/intermediate/format-detection.json`.
+
+Report: "Detected format: {format} (confidence: {confidence})"
+
+## Phase 3: ANALYZE
+
+Read the format detection result. Load the corresponding format guide:
+
+- `obsidian` → inject `skills/understand-knowledge/formats/obsidian.md`
+- `logseq` → inject `skills/understand-knowledge/formats/logseq.md`
+- `dendron` → inject `skills/understand-knowledge/formats/dendron.md`
+- `foam` → inject `skills/understand-knowledge/formats/foam.md`
+- `karpathy` → inject `skills/understand-knowledge/formats/karpathy.md`
+- `zettelkasten` → inject `skills/understand-knowledge/formats/zettelkasten.md`
+- `plain` → inject `skills/understand-knowledge/formats/plain.md`
+
+Batch the files from the manifest into groups of 15-25 files each.
+
+For each batch, dispatch an **article-analyzer** agent with:
+
+```json
+{
+ "projectRoot": "",
+ "batchFiles": [...],
+ "format": "",
+ "parsingHints": {...}
+}
+```
+
+Inject the format guide content into each agent's context.
+
+Run up to 5 batches concurrently.
+
+Wait for all `article-batch-*.json` files.
+
+Report: "Analyzed {totalFiles} files across {batchCount} batches."
+
+## Phase 4: RELATIONSHIPS
+
+Dispatch the **relationship-builder** agent.
+
+Wait for `.understand-anything/intermediate/relationships.json`.
+
+Report: "Discovered {topicCount} topics, {implicitEdgeCount} implicit relationships."
+
+## Phase 5: ASSEMBLE
+
+Merge all intermediate results into a single knowledge graph:
+
+1. Read all `article-batch-*.json` files — collect all nodes and edges
+2. Read `relationships.json` — merge in topic nodes, implicit edges, layers, and tour
+3. Deduplicate nodes by ID (keep the most complete version)
+4. Deduplicate edges by source+target+type
+5. Assemble into `KnowledgeGraph` format:
+
+```json
+{
+ "version": "1.0",
+ "kind": "knowledge",
+ "project": {
+ "name": "",
+ "languages": [],
+ "frameworks": [],
+ "description": "Knowledge base analyzed from format",
+ "analyzedAt": "",
+ "gitCommitHash": ""
+ },
+ "nodes": [...],
+ "edges": [...],
+ "layers": [...],
+ "tour": [...]
+}
+```
+
+## Phase 6: REVIEW
+
+Dispatch the existing **graph-reviewer** agent to validate:
+- All edge source/target IDs reference existing nodes
+- No orphan nodes (nodes with zero edges)
+- No duplicate node IDs
+- All layers reference existing nodes
+- Tour steps reference existing nodes
+
+Apply fixes from the reviewer.
+
+## Phase 7: SAVE
+
+1. Write `.understand-anything/knowledge-graph.json`
+2. Write `.understand-anything/meta.json`:
+ ```json
+ {
+ "lastAnalyzedAt": "",
+ "gitCommitHash": "",
+ "version": "1.0",
+ "analyzedFiles": ,
+ "knowledgeFormat": ""
+ }
+ ```
+3. Clean up `.understand-anything/intermediate/` directory
+4. Report: "Knowledge graph saved with {nodeCount} nodes and {edgeCount} edges."
+
+## Phase 8: DASHBOARD
+
+Auto-trigger `/understand-dashboard` to launch the visualization.
+
+## Incremental Mode (--ingest)
+
+When `--ingest ` is specified:
+
+1. Read the existing `knowledge-graph.json`
+2. Scan only the specified file(s) or folder
+3. Skip format detection (reuse format from existing graph's metadata)
+4. Run article-analyzer on only the new/changed files
+5. Run relationship-builder on new nodes against the full existing graph
+6. Merge new nodes/edges into the existing graph
+7. Re-run graph-reviewer
+8. Save updated graph
+```
+
+- [ ] **Step 2: Commit**
+
+```bash
+git add understand-anything-plugin/skills/understand-knowledge/SKILL.md
+git commit -m "feat(skill): add /understand-knowledge skill definition with 8-phase pipeline"
+```
+
+---
+
+## Task 14: Build, Test & Verify End-to-End
+
+**Files:**
+- All modified files
+
+- [ ] **Step 1: Build core package**
+
+Run: `pnpm --filter @understand-anything/core build`
+Expected: Clean build, no errors
+
+- [ ] **Step 2: Run core tests**
+
+Run: `pnpm --filter @understand-anything/core test -- --run`
+Expected: All tests pass, including new knowledge-schema tests
+
+- [ ] **Step 3: Build dashboard**
+
+Run: `pnpm --filter @understand-anything/dashboard build`
+Expected: Clean build, no errors
+
+- [ ] **Step 4: Run lint**
+
+Run: `pnpm lint`
+Expected: No lint errors
+
+- [ ] **Step 5: Verify skill is discoverable**
+
+Check that the skill file exists and has valid frontmatter:
+
+Run: `head -5 understand-anything-plugin/skills/understand-knowledge/SKILL.md`
+Expected: Valid `---` delimited YAML with name, description, argument-hint
+
+- [ ] **Step 6: Verify all agents are present**
+
+Run: `ls understand-anything-plugin/agents/ | grep knowledge\|format\|article\|relationship`
+Expected: `knowledge-scanner.md`, `format-detector.md`, `article-analyzer.md`, `relationship-builder.md`
+
+- [ ] **Step 7: Verify all format guides are present**
+
+Run: `ls understand-anything-plugin/skills/understand-knowledge/formats/`
+Expected: `obsidian.md`, `logseq.md`, `dendron.md`, `foam.md`, `karpathy.md`, `zettelkasten.md`, `plain.md`
+
+- [ ] **Step 8: Final commit**
+
+```bash
+git add -A
+git commit -m "feat: complete /understand-knowledge implementation — knowledge base analysis skill"
+```
From b2c2934291ed223d3efdc43e6d63bd71e869535c Mon Sep 17 00:00:00 2001
From: Lum1104
Date: Thu, 9 Apr 2026 23:11:44 +0800
Subject: [PATCH 04/11] docs: reorganize docs/ into superpowers/specs/ and
superpowers/plans/
Move all design docs to docs/superpowers/specs/ and all implementation
plans to docs/superpowers/plans/ for consistent organization.
Co-Authored-By: Claude Opus 4.6 (1M context)
---
docs/{ => superpowers}/plans/2026-03-14-phase1-implementation.md | 0
docs/{ => superpowers}/plans/2026-03-14-phase2-implementation.md | 0
docs/{ => superpowers}/plans/2026-03-14-phase3-implementation.md | 0
docs/{ => superpowers}/plans/2026-03-14-phase4-implementation.md | 0
.../{ => superpowers}/plans/2026-03-15-homepage-implementation.md | 0
.../plans/2026-03-18-multi-platform-simple-implementation.md | 0
docs/{ => superpowers}/plans/2026-03-21-language-agnostic-plan.md | 0
.../plans/2026-03-25-dashboard-robustness-impl.md | 0
.../plans/2026-03-25-dashboard-robustness-plan.md | 0
.../plans/2026-03-26-theme-system-implementation.md | 0
docs/{ => superpowers}/plans/2026-03-27-token-reduction-impl.md | 0
.../plans/2026-03-28-understand-anything-extension-impl.md | 0
docs/{ => superpowers}/plans/2026-03-29-homepage-update-impl.md | 0
.../plans/2026-04-01-business-domain-knowledge-impl.md | 0
.../specs}/2026-03-14-understand-anything-design.md | 0
docs/{plans => superpowers/specs}/2026-03-15-homepage-design.md | 0
.../specs}/2026-03-18-multi-platform-simple-design.md | 0
.../specs}/2026-03-21-language-agnostic-design.md | 0
.../specs}/2026-03-26-theme-system-design.md | 0
.../specs}/2026-03-27-token-reduction-design.md | 0
.../specs}/2026-03-28-understand-anything-extension-design.md | 0
.../specs}/2026-03-29-homepage-update-design.md | 0
.../specs}/2026-04-01-business-domain-knowledge-design.md | 0
23 files changed, 0 insertions(+), 0 deletions(-)
rename docs/{ => superpowers}/plans/2026-03-14-phase1-implementation.md (100%)
rename docs/{ => superpowers}/plans/2026-03-14-phase2-implementation.md (100%)
rename docs/{ => superpowers}/plans/2026-03-14-phase3-implementation.md (100%)
rename docs/{ => superpowers}/plans/2026-03-14-phase4-implementation.md (100%)
rename docs/{ => superpowers}/plans/2026-03-15-homepage-implementation.md (100%)
rename docs/{ => superpowers}/plans/2026-03-18-multi-platform-simple-implementation.md (100%)
rename docs/{ => superpowers}/plans/2026-03-21-language-agnostic-plan.md (100%)
rename docs/{ => superpowers}/plans/2026-03-25-dashboard-robustness-impl.md (100%)
rename docs/{ => superpowers}/plans/2026-03-25-dashboard-robustness-plan.md (100%)
rename docs/{ => superpowers}/plans/2026-03-26-theme-system-implementation.md (100%)
rename docs/{ => superpowers}/plans/2026-03-27-token-reduction-impl.md (100%)
rename docs/{ => superpowers}/plans/2026-03-28-understand-anything-extension-impl.md (100%)
rename docs/{ => superpowers}/plans/2026-03-29-homepage-update-impl.md (100%)
rename docs/{ => superpowers}/plans/2026-04-01-business-domain-knowledge-impl.md (100%)
rename docs/{plans => superpowers/specs}/2026-03-14-understand-anything-design.md (100%)
rename docs/{plans => superpowers/specs}/2026-03-15-homepage-design.md (100%)
rename docs/{plans => superpowers/specs}/2026-03-18-multi-platform-simple-design.md (100%)
rename docs/{plans => superpowers/specs}/2026-03-21-language-agnostic-design.md (100%)
rename docs/{plans => superpowers/specs}/2026-03-26-theme-system-design.md (100%)
rename docs/{plans => superpowers/specs}/2026-03-27-token-reduction-design.md (100%)
rename docs/{plans => superpowers/specs}/2026-03-28-understand-anything-extension-design.md (100%)
rename docs/{plans => superpowers/specs}/2026-03-29-homepage-update-design.md (100%)
rename docs/{plans => superpowers/specs}/2026-04-01-business-domain-knowledge-design.md (100%)
diff --git a/docs/plans/2026-03-14-phase1-implementation.md b/docs/superpowers/plans/2026-03-14-phase1-implementation.md
similarity index 100%
rename from docs/plans/2026-03-14-phase1-implementation.md
rename to docs/superpowers/plans/2026-03-14-phase1-implementation.md
diff --git a/docs/plans/2026-03-14-phase2-implementation.md b/docs/superpowers/plans/2026-03-14-phase2-implementation.md
similarity index 100%
rename from docs/plans/2026-03-14-phase2-implementation.md
rename to docs/superpowers/plans/2026-03-14-phase2-implementation.md
diff --git a/docs/plans/2026-03-14-phase3-implementation.md b/docs/superpowers/plans/2026-03-14-phase3-implementation.md
similarity index 100%
rename from docs/plans/2026-03-14-phase3-implementation.md
rename to docs/superpowers/plans/2026-03-14-phase3-implementation.md
diff --git a/docs/plans/2026-03-14-phase4-implementation.md b/docs/superpowers/plans/2026-03-14-phase4-implementation.md
similarity index 100%
rename from docs/plans/2026-03-14-phase4-implementation.md
rename to docs/superpowers/plans/2026-03-14-phase4-implementation.md
diff --git a/docs/plans/2026-03-15-homepage-implementation.md b/docs/superpowers/plans/2026-03-15-homepage-implementation.md
similarity index 100%
rename from docs/plans/2026-03-15-homepage-implementation.md
rename to docs/superpowers/plans/2026-03-15-homepage-implementation.md
diff --git a/docs/plans/2026-03-18-multi-platform-simple-implementation.md b/docs/superpowers/plans/2026-03-18-multi-platform-simple-implementation.md
similarity index 100%
rename from docs/plans/2026-03-18-multi-platform-simple-implementation.md
rename to docs/superpowers/plans/2026-03-18-multi-platform-simple-implementation.md
diff --git a/docs/plans/2026-03-21-language-agnostic-plan.md b/docs/superpowers/plans/2026-03-21-language-agnostic-plan.md
similarity index 100%
rename from docs/plans/2026-03-21-language-agnostic-plan.md
rename to docs/superpowers/plans/2026-03-21-language-agnostic-plan.md
diff --git a/docs/plans/2026-03-25-dashboard-robustness-impl.md b/docs/superpowers/plans/2026-03-25-dashboard-robustness-impl.md
similarity index 100%
rename from docs/plans/2026-03-25-dashboard-robustness-impl.md
rename to docs/superpowers/plans/2026-03-25-dashboard-robustness-impl.md
diff --git a/docs/plans/2026-03-25-dashboard-robustness-plan.md b/docs/superpowers/plans/2026-03-25-dashboard-robustness-plan.md
similarity index 100%
rename from docs/plans/2026-03-25-dashboard-robustness-plan.md
rename to docs/superpowers/plans/2026-03-25-dashboard-robustness-plan.md
diff --git a/docs/plans/2026-03-26-theme-system-implementation.md b/docs/superpowers/plans/2026-03-26-theme-system-implementation.md
similarity index 100%
rename from docs/plans/2026-03-26-theme-system-implementation.md
rename to docs/superpowers/plans/2026-03-26-theme-system-implementation.md
diff --git a/docs/plans/2026-03-27-token-reduction-impl.md b/docs/superpowers/plans/2026-03-27-token-reduction-impl.md
similarity index 100%
rename from docs/plans/2026-03-27-token-reduction-impl.md
rename to docs/superpowers/plans/2026-03-27-token-reduction-impl.md
diff --git a/docs/plans/2026-03-28-understand-anything-extension-impl.md b/docs/superpowers/plans/2026-03-28-understand-anything-extension-impl.md
similarity index 100%
rename from docs/plans/2026-03-28-understand-anything-extension-impl.md
rename to docs/superpowers/plans/2026-03-28-understand-anything-extension-impl.md
diff --git a/docs/plans/2026-03-29-homepage-update-impl.md b/docs/superpowers/plans/2026-03-29-homepage-update-impl.md
similarity index 100%
rename from docs/plans/2026-03-29-homepage-update-impl.md
rename to docs/superpowers/plans/2026-03-29-homepage-update-impl.md
diff --git a/docs/plans/2026-04-01-business-domain-knowledge-impl.md b/docs/superpowers/plans/2026-04-01-business-domain-knowledge-impl.md
similarity index 100%
rename from docs/plans/2026-04-01-business-domain-knowledge-impl.md
rename to docs/superpowers/plans/2026-04-01-business-domain-knowledge-impl.md
diff --git a/docs/plans/2026-03-14-understand-anything-design.md b/docs/superpowers/specs/2026-03-14-understand-anything-design.md
similarity index 100%
rename from docs/plans/2026-03-14-understand-anything-design.md
rename to docs/superpowers/specs/2026-03-14-understand-anything-design.md
diff --git a/docs/plans/2026-03-15-homepage-design.md b/docs/superpowers/specs/2026-03-15-homepage-design.md
similarity index 100%
rename from docs/plans/2026-03-15-homepage-design.md
rename to docs/superpowers/specs/2026-03-15-homepage-design.md
diff --git a/docs/plans/2026-03-18-multi-platform-simple-design.md b/docs/superpowers/specs/2026-03-18-multi-platform-simple-design.md
similarity index 100%
rename from docs/plans/2026-03-18-multi-platform-simple-design.md
rename to docs/superpowers/specs/2026-03-18-multi-platform-simple-design.md
diff --git a/docs/plans/2026-03-21-language-agnostic-design.md b/docs/superpowers/specs/2026-03-21-language-agnostic-design.md
similarity index 100%
rename from docs/plans/2026-03-21-language-agnostic-design.md
rename to docs/superpowers/specs/2026-03-21-language-agnostic-design.md
diff --git a/docs/plans/2026-03-26-theme-system-design.md b/docs/superpowers/specs/2026-03-26-theme-system-design.md
similarity index 100%
rename from docs/plans/2026-03-26-theme-system-design.md
rename to docs/superpowers/specs/2026-03-26-theme-system-design.md
diff --git a/docs/plans/2026-03-27-token-reduction-design.md b/docs/superpowers/specs/2026-03-27-token-reduction-design.md
similarity index 100%
rename from docs/plans/2026-03-27-token-reduction-design.md
rename to docs/superpowers/specs/2026-03-27-token-reduction-design.md
diff --git a/docs/plans/2026-03-28-understand-anything-extension-design.md b/docs/superpowers/specs/2026-03-28-understand-anything-extension-design.md
similarity index 100%
rename from docs/plans/2026-03-28-understand-anything-extension-design.md
rename to docs/superpowers/specs/2026-03-28-understand-anything-extension-design.md
diff --git a/docs/plans/2026-03-29-homepage-update-design.md b/docs/superpowers/specs/2026-03-29-homepage-update-design.md
similarity index 100%
rename from docs/plans/2026-03-29-homepage-update-design.md
rename to docs/superpowers/specs/2026-03-29-homepage-update-design.md
diff --git a/docs/plans/2026-04-01-business-domain-knowledge-design.md b/docs/superpowers/specs/2026-04-01-business-domain-knowledge-design.md
similarity index 100%
rename from docs/plans/2026-04-01-business-domain-knowledge-design.md
rename to docs/superpowers/specs/2026-04-01-business-domain-knowledge-design.md
From 55a03f66472ff327fa122c5fa532cc85cc24aadd Mon Sep 17 00:00:00 2001
From: Lum1104
Date: Sat, 11 Apr 2026 09:19:13 +0800
Subject: [PATCH 05/11] docs: add Star History rank badge to all READMEs
Co-Authored-By: Claude Opus 4.6 (1M context)
---
README.ja-JP.md | 10 ++++++++++
README.md | 10 ++++++++++
README.tr-TR.md | 10 ++++++++++
README.zh-CN.md | 10 ++++++++++
README.zh-TW.md | 10 ++++++++++
5 files changed, 50 insertions(+)
diff --git a/README.ja-JP.md b/README.ja-JP.md
index 7a68455..dd5fd59 100644
--- a/README.ja-JP.md
+++ b/README.ja-JP.md
@@ -10,6 +10,16 @@
English | 简体中文 | 繁體中文 | 日本語 | Türkçe
+
+
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
index ef87951..4081f6c 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,16 @@
English | 简体中文 | 繁體中文 | 日本語 | Türkçe
+
+
+
+
+
+
+
+
+
+
diff --git a/README.tr-TR.md b/README.tr-TR.md
index 39cab1b..96b278a 100644
--- a/README.tr-TR.md
+++ b/README.tr-TR.md
@@ -10,6 +10,16 @@
English | 简体中文 | 繁體中文 | 日本語 | Türkçe
+
+
+
+
+
+
+
+
+
+
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 62f722a..da80ab2 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -9,6 +9,16 @@
English | 简体中文 | 繁體中文 | 日本語 | Türkçe
+
+
+
+
+
+
+
+
+
+
diff --git a/README.zh-TW.md b/README.zh-TW.md
index 08aa44e..46d10a7 100644
--- a/README.zh-TW.md
+++ b/README.zh-TW.md
@@ -9,6 +9,16 @@
English | 简体中文 | 繁體中文 | 日本語 | Türkçe
+
+
+
+
+
+
+
+
+
+
From 2fc85e68c3975fc116e63c5a2e717e04816fd103 Mon Sep 17 00:00:00 2001
From: Lum1104
Date: Sun, 12 Apr 2026 11:09:41 +0800
Subject: [PATCH 06/11] feat: add /understand-knowledge for Karpathy LLM wiki
knowledge bases
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Support the Karpathy LLM wiki pattern — a three-layer architecture
(raw sources + wiki markdown + schema) with wikilinks, index.md
categories, and append-only log.md.
Pipeline:
- parse-knowledge-base.py: deterministic extraction of articles,
wikilinks, categories from index.md, source nodes from raw/
- article-analyzer agent: LLM-based entity/claim extraction and
implicit relationship discovery (builds_on, contradicts, etc.)
- merge-knowledge-graph.py: combines scan + analysis with entity
dedup, layer assignment from categories, tour generation
Dashboard:
- KnowledgeGraphView with d3-force layout (community clustering
by index.md categories, degree-proportional sizing)
- 5 knowledge node types (article, entity, topic, claim, source)
- 6 knowledge edge types with visual styling
- KnowledgeNodeDetails sidebar (wikilinks, backlinks, preview)
- Auto-detect kind:"knowledge" → knowledge-only view mode
Core:
- 5 node types + 6 edge types added to NodeType/EdgeType unions
- KnowledgeMeta interface (wikilinks, backlinks, category, content)
- kind field on KnowledgeGraph for view mode detection
- Zod schemas + node/edge type aliases
Co-Authored-By: Claude Opus 4.6 (1M context)
---
pnpm-lock.yaml | 37 +-
.../agents/article-analyzer.md | 93 ++++
.../packages/core/src/schema.ts | 43 +-
.../packages/core/src/types.ts | 22 +-
.../packages/dashboard/package.json | 6 +-
.../packages/dashboard/src/App.tsx | 32 +-
.../dashboard/src/components/CustomNode.tsx | 10 +
.../dashboard/src/components/GraphView.tsx | 1 +
.../src/components/KnowledgeGraphView.tsx | 260 +++++++++
.../dashboard/src/components/NodeInfo.tsx | 107 ++++
.../packages/dashboard/src/index.css | 7 +
.../packages/dashboard/src/store.ts | 24 +-
.../packages/dashboard/src/utils/layout.ts | 120 +++++
understand-anything-plugin/pnpm-lock.yaml | 27 +
.../skills/understand-knowledge/SKILL.md | 132 +++++
.../merge-knowledge-graph.py | 397 ++++++++++++++
.../parse-knowledge-base.py | 492 ++++++++++++++++++
17 files changed, 1775 insertions(+), 35 deletions(-)
create mode 100644 understand-anything-plugin/agents/article-analyzer.md
create mode 100644 understand-anything-plugin/packages/dashboard/src/components/KnowledgeGraphView.tsx
create mode 100644 understand-anything-plugin/skills/understand-knowledge/SKILL.md
create mode 100644 understand-anything-plugin/skills/understand-knowledge/merge-knowledge-graph.py
create mode 100644 understand-anything-plugin/skills/understand-knowledge/parse-knowledge-base.py
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 28627d0..f6efbda 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -82,6 +82,9 @@ importers:
'@xyflow/react':
specifier: ^12.0.0
version: 12.10.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ d3-force:
+ specifier: ^3.0.0
+ version: 3.0.0
devlop:
specifier: ^1.1.0
version: 1.1.0
@@ -104,6 +107,9 @@ importers:
'@tailwindcss/vite':
specifier: ^4.0.0
version: 4.2.1(vite@6.4.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.3))
+ '@types/d3-force':
+ specifier: ^3.0.10
+ version: 3.0.10
'@types/react':
specifier: ^19.0.0
version: 19.2.14
@@ -1011,6 +1017,9 @@ packages:
'@types/d3-drag@3.0.7':
resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==}
+ '@types/d3-force@3.0.10':
+ resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==}
+
'@types/d3-interpolate@3.0.4':
resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==}
@@ -1317,10 +1326,18 @@ packages:
resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
engines: {node: '>=12'}
+ d3-force@3.0.0:
+ resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==}
+ engines: {node: '>=12'}
+
d3-interpolate@3.0.1:
resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
engines: {node: '>=12'}
+ d3-quadtree@3.0.1:
+ resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==}
+ engines: {node: '>=12'}
+
d3-selection@3.0.0:
resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==}
engines: {node: '>=12'}
@@ -3345,6 +3362,8 @@ snapshots:
dependencies:
'@types/d3-selection': 3.0.11
+ '@types/d3-force@3.0.10': {}
+
'@types/d3-interpolate@3.0.4':
dependencies:
'@types/d3-color': 3.1.3
@@ -3447,14 +3466,6 @@ snapshots:
chai: 5.3.3
tinyrainbow: 2.0.0
- '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.3))':
- dependencies:
- '@vitest/spy': 3.2.4
- estree-walker: 3.0.3
- magic-string: 0.30.21
- optionalDependencies:
- vite: 7.3.1(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.3)
-
'@vitest/mocker@3.2.4(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.3))':
dependencies:
'@vitest/spy': 3.2.4
@@ -3762,10 +3773,18 @@ snapshots:
d3-ease@3.0.1: {}
+ d3-force@3.0.0:
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-quadtree: 3.0.1
+ d3-timer: 3.0.1
+
d3-interpolate@3.0.1:
dependencies:
d3-color: 3.1.0
+ d3-quadtree@3.0.1: {}
+
d3-selection@3.0.0: {}
d3-timer@3.0.1: {}
@@ -5297,7 +5316,7 @@ snapshots:
dependencies:
'@types/chai': 5.2.3
'@vitest/expect': 3.2.4
- '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.3))
+ '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.3))
'@vitest/pretty-format': 3.2.4
'@vitest/runner': 3.2.4
'@vitest/snapshot': 3.2.4
diff --git a/understand-anything-plugin/agents/article-analyzer.md b/understand-anything-plugin/agents/article-analyzer.md
new file mode 100644
index 0000000..013a8dd
--- /dev/null
+++ b/understand-anything-plugin/agents/article-analyzer.md
@@ -0,0 +1,93 @@
+---
+name: article-analyzer
+description: |
+ Analyzes markdown files using pre-parsed structural data and LLM inference to extract knowledge graph nodes and edges (entities, claims, implicit relationships, topic clustering).
+model: inherit
+---
+
+# Article Analyzer Agent
+
+You are a knowledge graph extraction expert. Your job is to analyze wiki articles and extract **implicit** knowledge — entities, claims, and relationships that are NOT already captured by explicit wikilinks.
+
+## Input
+
+You will receive a batch of articles as a JSON array. Each article has:
+- `id`: the article node ID (e.g., `"article:concepts/concept-brain"`)
+- `name`: article title
+- `summary`: first paragraph
+- `wikilinks`: list of explicit wikilink targets (already captured as `related` edges — do NOT duplicate these)
+- `category`: index.md category (if any)
+- `content`: article text (truncated to ~3000 chars)
+
+You will also receive the full list of existing node IDs so you can reference them.
+
+## Task
+
+For each article in the batch, extract:
+
+### 1. Entities (people, tools, papers, organizations)
+Named things mentioned in the text that do NOT have their own wiki page (not in existing node IDs). Create `entity` nodes.
+
+- `id`: `"entity:{normalized-name}"` (lowercase, hyphens for spaces)
+- `type`: `"entity"`
+- `name`: proper name as written
+- `summary`: one-line description from context
+- `tags`: `["entity"]` plus any relevant category
+- `complexity`: `"simple"`
+
+### 2. Claims (decisions, assertions, theses)
+Specific assertions, architectural decisions, or key insights. Create `claim` nodes.
+
+- `id`: `"claim:{article-stem}:{short-slug}"` (e.g., `"claim:decision-typescript-python:ts-core-py-clones"`)
+- `type`: `"claim"`
+- `name`: short claim title
+- `summary`: the assertion itself (1-2 sentences)
+- `tags`: `["claim"]` plus category
+- `complexity`: `"simple"`
+
+### 3. Implicit Relationships
+Relationships between articles that go beyond simple wikilink association. Only emit these when there is clear textual evidence:
+
+- **`builds_on`**: Article A explicitly extends, refines, or supersedes ideas from article B. Weight: 0.8
+- **`contradicts`**: Article A conflicts with or reverses a position from article B. Weight: 0.9
+- **`exemplifies`**: An entity or article is a concrete example of a concept. Weight: 0.7
+- **`authored_by`**: Article attributed to a specific entity (person/agent). Weight: 0.6
+- **`cites`**: Article references a raw source document. Weight: 0.7
+
+Edge format:
+```json
+{
+ "source": "article:...",
+ "target": "article:... or entity:... or claim:... or source:...",
+ "type": "builds_on",
+ "direction": "forward",
+ "weight": 0.8,
+ "description": "Brief reason for this relationship"
+}
+```
+
+## Rules
+
+1. **Do NOT duplicate wikilink edges.** The parse script already created `related` edges for every `[[wikilink]]`. Your job is to find what the wikilinks missed.
+2. **Be conservative.** Only create edges with clear textual evidence. A vague thematic similarity is not enough.
+3. **Deduplicate entities.** If the same person/tool appears in multiple articles, create the entity node once.
+4. **Use existing IDs.** When creating edges to existing articles, use their exact `id` from the provided node list.
+5. **Keep it small.** For a batch of 10-15 articles, expect ~5-15 entities, ~5-10 claims, and ~10-20 implicit edges. Don't over-extract.
+
+## Output Format
+
+Write a JSON file to `$INTERMEDIATE_DIR/analysis-batch-$BATCH_NUM.json`:
+
+```json
+{
+ "nodes": [
+ { "id": "entity:...", "type": "entity", "name": "...", "summary": "...", "tags": [...], "complexity": "simple" },
+ { "id": "claim:...", "type": "claim", "name": "...", "summary": "...", "tags": [...], "complexity": "simple" }
+ ],
+ "edges": [
+ { "source": "...", "target": "...", "type": "builds_on", "direction": "forward", "weight": 0.8, "description": "..." }
+ ]
+}
+```
+
+Do NOT include any article or topic nodes in your output — those already exist from the parse script. Only output NEW entity nodes, claim nodes, and implicit edges.
diff --git a/understand-anything-plugin/packages/core/src/schema.ts b/understand-anything-plugin/packages/core/src/schema.ts
index 88790a8..cc89e25 100644
--- a/understand-anything-plugin/packages/core/src/schema.ts
+++ b/understand-anything-plugin/packages/core/src/schema.ts
@@ -1,6 +1,6 @@
import { z } from "zod";
-// Edge types (29 values across 7 categories)
+// Edge types (35 values across 8 categories)
export const EdgeTypeSchema = z.enum([
"imports", "exports", "contains", "inherits", "implements", // Structural
"calls", "subscribes", "publishes", "middleware", // Behavioral
@@ -10,6 +10,7 @@ export const EdgeTypeSchema = z.enum([
"deploys", "serves", "provisions", "triggers", // Infrastructure
"migrates", "documents", "routes", "defines_schema", // Schema/Data
"contains_flow", "flow_step", "cross_domain", // Domain
+ "cites", "contradicts", "builds_on", "exemplifies", "categorized_under", "authored_by", // Knowledge
]);
// Aliases that LLMs commonly generate instead of canonical node types
@@ -55,6 +56,22 @@ export const NODE_TYPE_ALIASES: Record = {
business_process: "flow",
task: "step",
business_step: "step",
+ // Knowledge aliases
+ note: "article",
+ page: "article",
+ wiki_page: "article",
+ person: "entity",
+ actor: "entity",
+ organization: "entity",
+ tag: "topic",
+ category: "topic",
+ theme: "topic",
+ assertion: "claim",
+ decision: "claim",
+ thesis: "claim",
+ reference: "source",
+ raw: "source",
+ paper: "source",
};
// Aliases that LLMs commonly generate instead of canonical edge types
@@ -88,6 +105,20 @@ export const EDGE_TYPE_ALIASES: Record = {
has_flow: "contains_flow",
next_step: "flow_step",
interacts_with: "cross_domain",
+ // Knowledge aliases
+ references: "cites",
+ cites_source: "cites",
+ conflicts_with: "contradicts",
+ disagrees_with: "contradicts",
+ refines: "builds_on",
+ elaborates: "builds_on",
+ illustrates: "exemplifies",
+ instance_of: "exemplifies",
+ example_of: "exemplifies",
+ belongs_to: "categorized_under",
+ tagged_with: "categorized_under",
+ written_by: "authored_by",
+ created_by: "authored_by",
// Note: "implemented_by" is intentionally NOT aliased to "implements" —
// it inverts edge direction (see commit fd0df15). The LLM should use
// "implements" with correct source/target instead.
@@ -327,6 +358,13 @@ const DomainMetaSchema = z.object({
entryType: z.enum(["http", "cli", "event", "cron", "manual"]).optional(),
}).passthrough();
+const KnowledgeMetaSchema = z.object({
+ wikilinks: z.array(z.string()).optional(),
+ backlinks: z.array(z.string()).optional(),
+ category: z.string().optional(),
+ content: z.string().optional(),
+}).passthrough();
+
export const GraphNodeSchema = z.object({
id: z.string(),
type: z.enum([
@@ -334,6 +372,7 @@ export const GraphNodeSchema = z.object({
"config", "document", "service", "table", "endpoint",
"pipeline", "schema", "resource",
"domain", "flow", "step",
+ "article", "entity", "topic", "claim", "source",
]),
name: z.string(),
filePath: z.string().optional(),
@@ -343,6 +382,7 @@ export const GraphNodeSchema = z.object({
complexity: z.enum(["simple", "moderate", "complex"]),
languageNotes: z.string().optional(),
domainMeta: DomainMetaSchema.optional(),
+ knowledgeMeta: KnowledgeMetaSchema.optional(),
}).passthrough();
export const GraphEdgeSchema = z.object({
@@ -380,6 +420,7 @@ export const ProjectMetaSchema = z.object({
export const KnowledgeGraphSchema = z.object({
version: z.string(),
+ kind: z.enum(["codebase", "knowledge"]).optional(),
project: ProjectMetaSchema,
nodes: z.array(GraphNodeSchema),
edges: z.array(GraphEdgeSchema),
diff --git a/understand-anything-plugin/packages/core/src/types.ts b/understand-anything-plugin/packages/core/src/types.ts
index 106f25e..1617926 100644
--- a/understand-anything-plugin/packages/core/src/types.ts
+++ b/understand-anything-plugin/packages/core/src/types.ts
@@ -1,11 +1,12 @@
-// Node types (16 total: 5 code + 8 non-code + 3 domain)
+// Node types (21 total: 5 code + 8 non-code + 3 domain + 5 knowledge)
export type NodeType =
| "file" | "function" | "class" | "module" | "concept"
| "config" | "document" | "service" | "table" | "endpoint"
| "pipeline" | "schema" | "resource"
- | "domain" | "flow" | "step";
+ | "domain" | "flow" | "step"
+ | "article" | "entity" | "topic" | "claim" | "source";
-// Edge types (29 total in 7 categories: Structural, Behavioral, Data flow, Dependencies, Semantic, Infrastructure/Schema, Domain)
+// Edge types (35 total in 8 categories: Structural, Behavioral, Data flow, Dependencies, Semantic, Infrastructure/Schema, Domain, Knowledge)
export type EdgeType =
| "imports" | "exports" | "contains" | "inherits" | "implements" // Structural
| "calls" | "subscribes" | "publishes" | "middleware" // Behavioral
@@ -14,7 +15,16 @@ export type EdgeType =
| "related" | "similar_to" // Semantic
| "deploys" | "serves" | "provisions" | "triggers" // Infrastructure
| "migrates" | "documents" | "routes" | "defines_schema" // Schema/Data
- | "contains_flow" | "flow_step" | "cross_domain"; // Domain
+ | "contains_flow" | "flow_step" | "cross_domain" // Domain
+ | "cites" | "contradicts" | "builds_on" | "exemplifies" | "categorized_under" | "authored_by"; // Knowledge
+
+// Optional knowledge metadata for article/entity/topic/claim/source nodes
+export interface KnowledgeMeta {
+ wikilinks?: string[];
+ backlinks?: string[];
+ category?: string;
+ content?: string;
+}
// Optional domain metadata for domain/flow/step nodes
export interface DomainMeta {
@@ -25,7 +35,7 @@ export interface DomainMeta {
entryType?: "http" | "cli" | "event" | "cron" | "manual";
}
-// GraphNode with 16 types: 5 code + 8 non-code + 3 domain
+// GraphNode with 21 types: 5 code + 8 non-code + 3 domain + 5 knowledge
export interface GraphNode {
id: string;
type: NodeType;
@@ -37,6 +47,7 @@ export interface GraphNode {
complexity: "simple" | "moderate" | "complex";
languageNotes?: string;
domainMeta?: DomainMeta;
+ knowledgeMeta?: KnowledgeMeta;
}
// GraphEdge with rich relationship modeling
@@ -79,6 +90,7 @@ export interface ProjectMeta {
// Root KnowledgeGraph
export interface KnowledgeGraph {
version: string;
+ kind?: "codebase" | "knowledge";
project: ProjectMeta;
nodes: GraphNode[];
edges: GraphEdge[];
diff --git a/understand-anything-plugin/packages/dashboard/package.json b/understand-anything-plugin/packages/dashboard/package.json
index b9bdbe4..2702091 100644
--- a/understand-anything-plugin/packages/dashboard/package.json
+++ b/understand-anything-plugin/packages/dashboard/package.json
@@ -13,15 +13,17 @@
"@dagrejs/dagre": "^2.0.4",
"@understand-anything/core": "workspace:*",
"@xyflow/react": "^12.0.0",
- "react": "^19.0.0",
- "react-dom": "^19.0.0",
+ "d3-force": "^3.0.0",
"devlop": "^1.1.0",
"hast-util-to-jsx-runtime": "^2.3.6",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0",
"react-markdown": "^10.1.0",
"zustand": "^5.0.0"
},
"devDependencies": {
"@tailwindcss/vite": "^4.0.0",
+ "@types/d3-force": "^3.0.10",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@vitejs/plugin-react": "^4.3.0",
diff --git a/understand-anything-plugin/packages/dashboard/src/App.tsx b/understand-anything-plugin/packages/dashboard/src/App.tsx
index c6e262e..71a2555 100644
--- a/understand-anything-plugin/packages/dashboard/src/App.tsx
+++ b/understand-anything-plugin/packages/dashboard/src/App.tsx
@@ -4,6 +4,7 @@ import type { GraphIssue } from "@understand-anything/core/schema";
import { useDashboardStore } from "./store";
import GraphView from "./components/GraphView";
import DomainGraphView from "./components/DomainGraphView";
+import KnowledgeGraphView from "./components/KnowledgeGraphView";
import CodeViewer from "./components/CodeViewer";
import SearchBar from "./components/SearchBar";
import NodeInfo from "./components/NodeInfo";
@@ -104,6 +105,7 @@ function Dashboard({ accessToken }: { accessToken: string }) {
const [metaTheme, setMetaTheme] = useState(null);
const viewMode = useDashboardStore((s) => s.viewMode);
const setViewMode = useDashboardStore((s) => s.setViewMode);
+ const isKnowledgeGraph = useDashboardStore((s) => s.isKnowledgeGraph);
const domainGraph = useDashboardStore((s) => s.domainGraph);
const setDomainGraph = useDashboardStore((s) => s.setDomainGraph);
@@ -240,6 +242,11 @@ function Dashboard({ accessToken }: { accessToken: string }) {
if (result.success && result.data) {
setGraph(result.data);
setGraphIssues(result.issues);
+ // Auto-detect knowledge graph kind
+ if ((data as Record).kind === "knowledge") {
+ setViewMode("knowledge");
+ useDashboardStore.getState().setIsKnowledgeGraph(true);
+ }
for (const issue of result.issues) {
if (issue.level === "auto-corrected") {
console.warn(`[graph] auto-corrected: ${issue.message}`);
@@ -331,7 +338,7 @@ function Dashboard({ accessToken }: { accessToken: string }) {
- {graph && domainGraph && (
+ {graph && !isKnowledgeGraph && domainGraph && (
<>
@@ -369,14 +376,17 @@ function Dashboard({ accessToken }: { accessToken: string }) {
- {([
- { key: "code", label: "Code", color: "var(--color-node-file)" },
- { key: "config", label: "Config", color: "var(--color-node-config)" },
- { key: "docs", label: "Docs", color: "var(--color-node-document)" },
- { key: "infra", label: "Infra", color: "var(--color-node-service)" },
- { key: "data", label: "Data", color: "var(--color-node-table)" },
- { key: "domain", label: "Domain", color: "var(--color-node-concept)" },
- ] as const).map((cat) => (
+ {(isKnowledgeGraph ? [
+ { key: "knowledge" as const, label: "All", color: "var(--color-node-article)" },
+ ] : [
+ { key: "code" as const, label: "Code", color: "var(--color-node-file)" },
+ { key: "config" as const, label: "Config", color: "var(--color-node-config)" },
+ { key: "docs" as const, label: "Docs", color: "var(--color-node-document)" },
+ { key: "infra" as const, label: "Infra", color: "var(--color-node-service)" },
+ { key: "data" as const, label: "Data", color: "var(--color-node-table)" },
+ { key: "domain" as const, label: "Domain", color: "var(--color-node-concept)" },
+ { key: "knowledge" as const, label: "Knowledge", color: "var(--color-node-article)" },
+ ]).map((cat) => (