.claude/skills/knowledge-graph/SKILL.md
Entity and relation tracking skill using MCP memory server patterns and local knowledge graph storage. Build persistent knowledge graphs of entities, relationships, and observations across agent sessions. Covers the MCP memory server (@modelcontextprotocol/server-memory), local JSON-based graphs, and entity-relation querying patterns for long-running agents.
npx skillsauth add oimiragieo/agent-studio knowledge-graphInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Build and query persistent knowledge graphs of entities, relationships, and observations across agent sessions. Enables agents to accumulate structured knowledge over time — tracking what they've learned about projects, people, codebases, and domains.
Skill({ skill: 'knowledge-graph' }) when:
The official MCP memory server provides a persistent knowledge graph accessible via tool calls.
npx -y @modelcontextprotocol/server-memory
Claude Desktop / settings.json config:
{
"mcpServers": {
"memory": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory"],
"env": {
"MEMORY_FILE_PATH": ".claude/context/memory/knowledge-graph.json"
}
}
}
}
| Tool | Purpose |
| --------------------- | --------------------------------------------------- |
| create_entities | Add one or more entities with type and observations |
| create_relations | Add directed relations between entities |
| add_observations | Append new observations to existing entities |
| delete_entities | Remove entities (and their relations) |
| delete_observations | Remove specific observations |
| delete_relations | Remove specific relations |
| read_graph | Return the full graph |
| search_nodes | Search entities by query string |
| open_nodes | Retrieve specific entities by name |
// Create entities
mcp__memory__create_entities({
entities: [
{
name: 'authentication-service',
entityType: 'service',
observations: [
'Handles JWT authentication and refresh token rotation',
'Located at src/auth/',
'Uses Redis for token storage',
'Rate-limited to 100 req/min per IP',
],
},
{
name: 'Alice Chen',
entityType: 'person',
observations: ['Senior engineer, owns the auth service', 'On-call for auth incidents'],
},
],
});
// Create relations
mcp__memory__create_relations({
relations: [
{
from: 'Alice Chen',
to: 'authentication-service',
relationType: 'owns',
},
],
});
// Add new observations as you learn more
mcp__memory__add_observations({
observations: [
{
entityName: 'authentication-service',
contents: ['Migrated to Argon2 password hashing in March 2026'],
},
],
});
// Search for relevant nodes
mcp__memory__search_nodes({ query: 'authentication' });
// Retrieve specific entities
mcp__memory__open_nodes({ names: ['authentication-service', 'Alice Chen'] });
At the start of every agent session that uses knowledge graphs:
// 1. Load existing graph context
const existing = await mcp__memory__read_graph({});
// Review existing entities for this domain
// 2. Search for relevant entities
const relevant = await mcp__memory__search_nodes({ query: '<current task domain>' });
// 3. Update entities with new observations from this session
// ... do work ...
// 4. Before session end, add observations for key discoveries
await mcp__memory__add_observations({
observations: [
{
entityName: 'my-project',
contents: [`Session ${new Date().toISOString()}: Discovered X, fixed Y`],
},
],
});
For agents without MCP memory server access, use a local JSON file:
import json
import uuid
from datetime import datetime, timezone
from pathlib import Path
GRAPH_PATH = Path(".claude/context/memory/knowledge-graph.json")
def load_graph() -> dict:
if GRAPH_PATH.exists():
return json.loads(GRAPH_PATH.read_text())
return {"entities": {}, "relations": []}
def save_graph(graph: dict):
GRAPH_PATH.parent.mkdir(parents=True, exist_ok=True)
GRAPH_PATH.write_text(json.dumps(graph, indent=2))
def add_entity(graph: dict, name: str, entity_type: str, observations: list[str]) -> str:
"""Add or update an entity. Returns entity ID."""
# Check if entity with this name exists
for eid, entity in graph["entities"].items():
if entity["name"] == name:
entity["observations"].extend(observations)
entity["updated_at"] = datetime.now(timezone.utc).isoformat()
return eid
# Create new entity
eid = str(uuid.uuid4())[:8]
graph["entities"][eid] = {
"id": eid,
"name": name,
"type": entity_type,
"observations": observations,
"created_at": datetime.now(timezone.utc).isoformat(),
"updated_at": datetime.now(timezone.utc).isoformat(),
}
return eid
def add_relation(graph: dict, from_name: str, to_name: str, relation_type: str):
"""Add a directed relation between two entities by name."""
graph["relations"].append({
"from": from_name,
"to": to_name,
"type": relation_type,
"created_at": datetime.now(timezone.utc).isoformat(),
})
def search_entities(graph: dict, query: str) -> list[dict]:
"""Search entities by name, type, or observation content."""
query_lower = query.lower()
results = []
for entity in graph["entities"].values():
if (query_lower in entity["name"].lower()
or query_lower in entity["type"].lower()
or any(query_lower in obs.lower() for obs in entity["observations"])):
results.append(entity)
return results
def get_entity_relations(graph: dict, entity_name: str) -> dict:
"""Get all relations for an entity (outgoing and incoming)."""
outgoing = [r for r in graph["relations"] if r["from"] == entity_name]
incoming = [r for r in graph["relations"] if r["to"] == entity_name]
return {"outgoing": outgoing, "incoming": incoming}
# Usage
graph = load_graph()
auth_id = add_entity(graph, "authentication-service", "service", [
"Handles JWT authentication",
"Located at src/auth/",
"Uses Redis for token storage",
])
add_entity(graph, "Alice Chen", "person", [
"Senior engineer, owns the auth service",
])
add_relation(graph, "Alice Chen", "authentication-service", "owns")
save_graph(graph)
# Query
results = search_entities(graph, "auth")
relations = get_entity_relations(graph, "Alice Chen")
interface Entity {
id: string; // Stable UUID (never changes)
name: string; // Human-readable identifier
type: EntityType; // Normalized type string
observations: string[]; // Timestamped facts (append-only)
created_at: string; // ISO 8601
updated_at: string; // ISO 8601
}
interface Relation {
from: string; // Entity name (source)
to: string; // Entity name (target)
type: string; // Directional verb: "owns", "depends_on", "calls", "manages"
created_at: string;
}
// Common entity types
type EntityType =
| 'person'
| 'service'
| 'codebase'
| 'file'
| 'concept'
| 'organization'
| 'tool'
| 'decision'
| 'issue'
| 'feature';
| Relation | Direction | Example |
| --------------- | ----------------- | ----------------------------------- |
| owns | person → service | Alice owns auth-service |
| depends_on | service → service | api-gateway depends_on auth-service |
| calls | service → service | checkout calls payment-processor |
| manages | person → person | CTO manages engineering team |
| implements | service → concept | auth-service implements JWT |
| documented_in | feature → file | login documented_in README |
| fixes | commit → issue | fix/abc123 fixes issue-456 |
| blocks | issue → issue | JIRA-100 blocks JIRA-101 |
Build a knowledge graph of a codebase as you explore it:
// As you discover things about a codebase, record them
async function recordCodebaseDiscovery(findings: Discovery[]) {
const entities = findings.map(f => ({
name: f.componentName,
entityType: f.type, // "module", "class", "service", "database"
observations: f.observations,
}));
await mcp__memory__create_entities({ entities });
const relations = findings.flatMap(f =>
f.dependencies.map(dep => ({
from: f.componentName,
to: dep,
relationType: "depends_on",
}))
);
if (relations.length > 0) {
await mcp__memory__create_relations({ relations });
}
}
// Session startup: check what we already know
async function loadCodebaseContext(projectName: string) {
const graph = await mcp__memory__search_nodes({ query: projectName });
if (graph.entities.length > 0) {
console.log(`Loaded ${graph.entities.length} known entities for ${projectName}`);
return graph;
}
return null; // Fresh start
}
MEMORY_FILE_PATH env var → default: in-memory (not persisted).claude/context/memory/knowledge-graph.json.claude/context/memory/kg-<project-name>.jsonsearch_nodes with specific queriesmemory-search — Semantic search over agent memorycontext-compressor — Compress large knowledge graphs when approaching token limitsmcp-builder — Build custom MCP servers for specialized knowledge graph backendsBefore starting any task:
# Check what the agent already knows
mcp__memory__search_nodes({ query: "<task domain>" })
After completing work:
// Record key discoveries as observations
mcp__memory__add_observations({
observations: [
{
entityName: '<project-or-domain>',
contents: ['<what was learned this session>'],
},
],
});
ASSUME INTERRUPTION: Your context may reset. If it's not in memory, it didn't happen.
tools
Comprehensive biosignal processing toolkit for analyzing physiological data including ECG, EEG, EDA, RSP, PPG, EMG, and EOG signals. Use this skill when processing cardiovascular signals, brain activity, electrodermal responses, respiratory patterns, muscle activity, or eye movements. Applicable for heart rate variability analysis, event-related potentials, complexity measures, autonomic nervous system assessment, psychophysiology research, and multi-modal physiological signal integration.
tools
Comprehensive toolkit for creating, analyzing, and visualizing complex networks and graphs in Python. Use when working with network/graph data structures, analyzing relationships between entities, computing graph algorithms (shortest paths, centrality, clustering), detecting communities, generating synthetic networks, or visualizing network topologies. Applicable to social networks, biological networks, transportation systems, citation networks, and any domain involving pairwise relationships.
data-ai
Molecular featurization for ML (100+ featurizers). ECFP, MACCS, descriptors, pretrained models (ChemBERTa), convert SMILES to features, for QSAR and molecular ML.
development
Run Python code in the cloud with serverless containers, GPUs, and autoscaling. Use when deploying ML models, running batch processing jobs, scheduling compute-intensive tasks, or serving APIs that require GPU acceleration or dynamic scaling.