Zettelkasten Memory
The SmartMemory system includes a powerful Zettelkasten memory type that implements atomic, interconnected knowledge management inspired by the traditional Zettelkasten method used by researchers and knowledge workers.
What is Zettelkasten Memory?
Zettelkasten (German for "slip box") is a method of knowledge management that stores atomic ideas as individual notes with unique identifiers and creates dense networks of cross-references between related concepts.
Key Characteristics:
- Atomic Notes: Each memory item contains a single, focused idea
- Unique Identifiers: Every note has a permanent, linkable ID
- Bidirectional Linking: Notes automatically link to related content
- Emergent Structure: Knowledge organization emerges from connections
- Contextual Discovery: Find information through associative pathways
How It Works in SmartMemory
Creating Notes
Zettel notes are a first-class core memory type (zettel). The supported public
way to create one is through the standard SmartMemory write API with
memory_type="zettel":
from smartmemory import SmartMemory, MemoryItem
memory = SmartMemory()
# Store a note explicitly typed as a zettel
item_id = memory.add(MemoryItem(
content="Machine learning models require large datasets for training effectiveness",
memory_type="zettel",
metadata={"title": "ML data requirements", "tags": ["#ml", "#data", "#training"]},
))Over the REST API, the dedicated POST /memory/zettel/notes endpoint creates a
note directly without LLM re-classification:
curl -X POST "$API_URL/memory/zettel/notes" \
-H "Authorization: Bearer $TOKEN" -H "X-Team-Id: $TEAM" \
-H "Content-Type: application/json" \
-d '{
"content": "Machine learning models require large datasets for training effectiveness",
"title": "ML data requirements",
"tags": ["#ml", "#data", "#training"]
}'
# → { "note_id": "...", "memory_type": "zettel", "title": "...", "tags": [...] }When notes are created, the system:
- Parses
[[wikilinks]],#hashtags, and concept references from the content - Resolves wikilink titles to existing notes and writes bidirectional
LINKS_TOedges - Stores tags and title as queryable properties on the note
- Builds an interconnected knowledge graph
Notes can also be derived automatically: the
EpisodicToZettelEvolverpromotes qualifying episodic memories into zettel notes during evolution (originevolver:episodic_to_zettel).
Bidirectional Auto-Linking
When you add new notes, the system automatically:
- Wikilink Linking: Parses
[[Target]]references and creates bidirectionalLINKS_TOedges to resolved notes - Backlink Tracking: Every link is queryable from both directions via
get_backlinks()andnotes_linked_to() - Dynamic Relations: Arbitrary typed relations (e.g.
INSPIRED_BY,CONTRADICTS,ELABORATES_ON) can be added between notes - Tag / Concept Linking: Notes are discoverable by shared tags, concepts, and mentioned entities
Example: Linking Notes with Wikilinks
from smartmemory import SmartMemory, MemoryItem
memory = SmartMemory()
# Add foundational concepts
memory.add(MemoryItem(content="Neural networks learn through backpropagation",
memory_type="zettel",
metadata={"title": "backpropagation", "tags": ["#neural-networks"]}))
memory.add(MemoryItem(content="Gradient descent optimizes model parameters",
memory_type="zettel",
metadata={"title": "gradient-descent", "tags": ["#optimization"]}))
# Add a related concept that explicitly references the earlier notes.
# The [[wikilinks]] resolve to existing notes and create bidirectional edges.
memory.add(MemoryItem(
content="Deep learning combines [[backpropagation]] and [[gradient-descent]] across many layers",
memory_type="zettel",
metadata={"title": "deep-learning"},
))Interactive Graph Visualization
The system includes a React-based graph viewer that lets you:
- Visualize connections between all your notes
- Navigate associatively by clicking through related concepts
- Discover knowledge gaps by seeing sparse areas
- Track knowledge growth over time
The subgraph backing a viewer is served by GET /memory/zettel/{note_id}/graph,
which returns the notes and edges around a starting note for rendering.
Graph Maintenance and Analytics
The Zettelkasten memory exposes maintenance and analysis utilities on the
ZettelMemory class:
Linking
- Wikilink resolution:
[[Target]]references resolve to existing notes and write bidirectionalLINKS_TOedges - Auto-link toggle:
enable_auto_linking()/disable_auto_linking()control whether new notes are wikilink-parsed (auto_linkflag) - Dynamic relations:
add_dynamic_relation()adds arbitrary typed edges
Pruning
- Low-quality / duplicate detection:
get_low_quality_or_duplicates(...)returns prune candidates (short content, few connections, high Jaccard similarity) - Soft delete:
prune_or_merge(item)archives a note rather than hard-deleting it
Analytics
- Knowledge clusters:
detect_knowledge_clusters()finds emergent groupings - Bridges and emergence:
find_knowledge_bridges(),detect_concept_emergence() - System overview:
get_zettelkasten_overview()reports total notes, total connections, connection density, cluster count, and health - Knowledge density: Connectivity and coverage analysis
Integration with Other Memory Types
Zettelkasten memory works seamlessly with other SmartMemory types:
Evolution from Episodic Memory
# Episodic memories can be promoted into Zettel notes by the
# EpisodicToZettelEvolver during the pipeline's evolve stage.
# These derived notes carry origin="evolver:episodic_to_zettel".
memory.add(MemoryItem(content="Learning about transformers", memory_type="episodic"))
# During evolve, qualifying episodic items are re-derived as zettel notes
# and linked into the existing knowledge graph.Retrieving and Reading Notes
# Zettel notes are retrieved through the standard SmartMemory read API.
item = memory.get(item_id) # fetch a single note by id
results = memory.search("transformers") # full-text / vector search across memoryNote: there is no public "promote zettel → semantic" method. Cross-type transformation happens through the evolution pipeline, not a direct call.
Best Practices
Atomic Note Principle
✅ Good: "Attention mechanisms allow models to focus on relevant input parts" ❌ Bad: "Transformers use attention and are good for NLP and have encoder-decoder..."
Effective Tagging
# Tags are passed in the note's metadata and stored as queryable properties.
memory.add(MemoryItem(
content="Attention mechanisms allow models to focus on relevant input parts",
memory_type="zettel",
metadata={
"title": "attention-mechanism",
# Use hierarchical tags spanning domain and granularity
"tags": ["#ml/attention", "#architecture/transformer", "#concept"],
},
))Cross-Reference Patterns
# In your note content
This builds on [[gradient-descent.md]] and relates to [[neural-networks.md]].
See also: [[backpropagation.md]], [[optimization-theory.md]]Advanced Features
These methods live on the ZettelMemory class. Construct it directly when you
need the richer graph-analysis surface beyond simple create/read:
from smartmemory.memory.types.zettel_memory import ZettelMemory
zettel = ZettelMemory()Backlinks and Connections
# All notes that link TO a given note
backlinks = zettel.get_backlinks(note_id)
# Complete bidirectional view (incoming + outgoing) of a note's connections
connections = zettel.get_bidirectional_connections(note_id)
# Explicit typed relations between notes
zettel.add_dynamic_relation(source_id, target_id, "ELABORATES_ON")Emergent Structure
# Detect emergent knowledge clusters from connection patterns
clusters = zettel.detect_knowledge_clusters(min_cluster_size=3)
# Find notes that bridge different knowledge domains
bridges = zettel.find_knowledge_bridges()
# Detect concepts that are emerging from connection patterns
emerging = zettel.detect_concept_emergence()Serendipitous Discovery
# Suggest related notes for a starting note
suggestions = zettel.suggest_related_notes(note_id, suggestion_count=5)
# Find paths between two notes through the graph
paths = zettel.find_knowledge_paths(start_note_id, end_note_id, max_depth=5)
# Random walk for serendipitous exploration
walk = zettel.random_walk_discovery(note_id, walk_length=5)Note on imports/integration: there is no built-in Obsidian importer or graph-export method on
ZettelMemory. External vault import is handled by the separate vault-sync application surface, and graph data for visualization is served by the RESTGET /memory/zettel/{note_id}/graphendpoint rather than a Pythonexport_graphcall.
Use Cases
Research & Learning
- Literature review: Connect papers, concepts, and insights
- Course notes: Build interconnected understanding across subjects
- Project documentation: Link decisions, implementations, and learnings
Software Development
- Architecture documentation: Connect components, patterns, and decisions
- Code knowledge: Link algorithms, implementations, and examples
- Bug tracking: Connect issues, solutions, and root causes
Creative Work
- Idea development: Connect inspirations, concepts, and iterations
- Project planning: Link requirements, resources, and constraints
- Knowledge synthesis: Combine insights from multiple domains
API Reference
Creating and reading notes (SmartMemory)
from smartmemory import SmartMemory, MemoryItem
memory = SmartMemory()
# Create a zettel note
item_id = memory.add(MemoryItem(content, memory_type="zettel", metadata={"title": ..., "tags": [...]}))
# Retrieve and search
note = memory.get(item_id)
results = memory.search(query, top_k=10)Graph operations (ZettelMemory)
from smartmemory.memory.types.zettel_memory import ZettelMemory
zettel = ZettelMemory()
# Tag / property / relation queries
notes = zettel.find_notes_by_tag(tag_name)
notes = zettel.find_notes_by_property(key, value)
notes = zettel.notes_linked_to(note_id)
notes = zettel.notes_mentioning(entity_id)
notes = zettel.query_by_dynamic_relation(source_id, relation_type)
# Links and backlinks
backlinks = zettel.get_backlinks(note_id)
connections = zettel.get_bidirectional_connections(note_id)
zettel.create_bidirectional_link(source_id, target_id, link_type="LINKS_TO")
zettel.add_dynamic_relation(source_id, target_id, relation_type)
# Emergent structure
clusters = zettel.detect_knowledge_clusters(min_cluster_size=3)
bridges = zettel.find_knowledge_bridges()
emerging = zettel.detect_concept_emergence()
# Discovery
suggestions = zettel.suggest_related_notes(note_id, suggestion_count=5)
paths = zettel.find_knowledge_paths(start_note_id, end_note_id, max_depth=5)
walk = zettel.random_walk_discovery(note_id, walk_length=5)
# Wikilink parsing and system overview
parsed = zettel.parse_wikilinks(content) # → {wikilinks, concepts, hashtags}
overview = zettel.get_zettelkasten_overview() # totals, density, clusters, healthREST endpoints (/memory/zettel/*)
POST /memory/zettel/notes Create a note
GET /memory/zettel/by-tag/{tag} Notes by tag
GET /memory/zettel/by-property Notes by property (key, value)
GET /memory/zettel/mentioning/{entity_id} Notes mentioning an entity
GET /memory/zettel/{note_id}/backlinks Incoming links
GET /memory/zettel/{note_id}/forward-links Outgoing links
GET /memory/zettel/{note_id}/connections All connections
GET /memory/zettel/{note_id}/path/{target_id} Path between two notes
GET /memory/zettel/{note_id}/suggestions Suggested related notes
GET /memory/zettel/{note_id}/graph Subgraph for visualization
GET /memory/zettel/clusters Knowledge clusters
GET /memory/zettel/bridges Bridge notes
GET /memory/zettel/concept-emergence Emerging concepts
POST /memory/zettel/wikilink/parse Parse wikilinks from contentConfiguration
The main runtime knob is automatic wikilink linking, controlled by the
auto_link constructor flag (default True) and the toggle methods:
from smartmemory.memory.types.zettel_memory import ZettelMemory
# Disable automatic wikilink parsing at construction time
zettel = ZettelMemory(auto_link=False)
# Or toggle it at runtime
zettel.enable_auto_linking()
zettel.disable_auto_linking()Broader memory configuration (storage backend, embeddings, scoping) is supplied
through the standard MemoryConfig passed to ZettelMemory(config=...) /
SmartMemory, the same as every other memory type.
The Zettelkasten memory type transforms SmartMemory into a powerful knowledge management system that grows smarter and more connected over time, supporting both personal learning and collaborative knowledge building.