| name | claude-code-memory-obsidian-graphify |
| description | Set up persistent memory and knowledge graphs for Claude Code using Obsidian Zettelkasten and Graphify to reduce tokens by up to 71.5x |
| triggers | ["set up claude code memory with obsidian","configure persistent memory for coding agent","implement zettelkasten for claude code","reduce token usage with graphify","create knowledge graph for codebase","set up obsidian vault for claude","configure chat import pipeline","implement second brain for coding"] |
Claude Code Memory with Obsidian + Graphify
Skill by ara.so — Claude Code Skills collection.
This skill enables you to set up a persistent memory system for Claude Code that reduces token consumption by up to 71.5x through Obsidian Zettelkasten notes and Graphify knowledge graphs. You'll maintain context across sessions, eliminate codebase re-reading, and preserve conversation history.
What This System Does
Solves Two Core Problems:
- Session Amnesia: Claude Code forgets everything between sessions — you constantly re-explain your stack, decisions, and progress
- Token Waste: Re-reading ~40 files costs ~20k tokens per session just for orientation
Three-Layer Solution:
- Obsidian Vault: Centralized Zettelkasten with atomic notes, wikilinks, and YAML frontmatter for persistent project memory
- Graphify: AST-based codebase knowledge graphs that replace file re-reading with efficient queries
- Chat Import Pipeline: Python script + cron job to preserve Claude conversation insights as vault notes
Prerequisites
pip install graphifyy
pip install claude-conversation-extractor
Installation & Setup
1. Install Graphify
pip install graphifyy
graphify install --platform claude
ls ~/.claude/skills/graphify/SKILL.md
2. Configure API Keys
export ANTHROPIC_API_KEY="sk-ant-your-key-here"
export MOONSHOT_API_KEY="your-moonshot-key"
source ~/.bashrc
3. Create Obsidian Vault Structure
mkdir -p ~/vault/{permanent,inbox,fleeting,templates,logs,references}
mkdir -p ~/vault/chats/{code,web}
mkdir -p ~/vault/graphify
PROJECT_NAME="my-project"
mkdir -p ~/vault/$PROJECT_NAME/{architecture,pipeline,data,features,logs}
4. Create CLAUDE.md Configuration
Create ~/vault/CLAUDE.md:
# Vault — Instructions for Claude Code
## What is this vault
Centralized knowledge base for all projects.
Persistent memory across sessions using Zettelkasten method.
## Zettelkasten Rules
### Note creation
- Use wikilinks: [[note-name]] (not markdown links)
- Mandatory YAML frontmatter on every note
- Filenames in kebab-case: `auth-flow.md`, not `Auth Flow.md`
- 1 concept per permanent note (atomicity)
- Minimum 2 wikilinks per note (dense linking)
### Standard frontmatter
---
title: Note Name
tags: [project, topic]
created: YYYY-MM-DD
updated: YYYY-MM-DD
status: active
type: permanent
---
### Never do
- Don't delete notes without asking
- Don't use markdown links for internal notes
- Don't create notes without frontmatter
- Don't change folder structure without documenting
## Session Commands
### /resume
1. Read 3 most recent session logs in logs/
2. Read architecture/decisions.md for current project
3. Summarize current state and pending work
### /save
1. Create session log in logs/YYYY-MM-DD-description.md
2. Record: completed work, decisions, pending items
3. Add wikilinks to created/modified notes
4. Run git commit + push if in repository
5. Set Up Chat Import Pipeline
Create ~/scripts/claude_to_obsidian.py:
import os
import re
import argparse
from pathlib import Path
from datetime import datetime
KEYWORD_TAG_MAP = {
"python": "python",
"react": "react",
"typescript": "typescript",
"supabase": "supabase",
"deploy": "deploy",
"bug": "debugging",
"refactor": "refactoring",
"api": "api",
"database": "database",
"auth": "authentication",
"error": "debugging",
"test": "testing",
}
def extract_tags_from_content(content):
"""Extract tags based on keywords in content."""
tags = set(["chat-import"])
content_lower = content.lower()
for keyword, tag in KEYWORD_TAG_MAP.items():
if keyword in content_lower:
tags.add(tag)
return sorted(list(tags))
def find_wikilinks(content, vault_dir):
vault_path = Path(vault_dir)
existing_notes = {}
md_file vault_path.rglob():
note_name = md_file.stem
existing_notes[note_name.lower()] = note_name
note_lower, note_name existing_notes.items():
pattern =
content = re.sub(
pattern,
,
content,
flags=re.IGNORECASE
)
content
():
(file_path, , encoding=) f:
content = f.read()
title_match = re.search(, content, re.MULTILINE)
title = title_match.group() title_match Path(file_path).stem
date_match = re.search(, Path(file_path).stem)
date = date_match.group() date_match datetime.now().strftime()
tags = extract_tags_from_content(content)
origin == :
tags.append()
origin == :
tags.append()
content = find_wikilinks(content, vault_dir)
frontmatter =
content.startswith():
content = re.sub(, , content, flags=re.DOTALL)
final_content = frontmatter + content.strip()
final_content, title, date
():
parser = argparse.ArgumentParser(description=)
parser.add_argument(, required=, =)
parser.add_argument(, required=, =)
parser.add_argument(, action=, =)
args = parser.parse_args()
export_dir = Path(args.export_dir)
vault_dir = Path(args.vault_dir)
origin [, ]:
source_dir = export_dir / origin
target_dir = vault_dir / / origin
source_dir.exists():
target_dir.mkdir(parents=, exist_ok=)
chat_file source_dir.glob():
:
processed_content, title, date = process_chat(
chat_file, vault_dir, origin
)
safe_title = re.sub(, , title)
safe_title = re.sub(, , safe_title).strip()
filename =
target_file = target_dir / filename
(target_file, , encoding=) f:
f.write(processed_content)
()
args.move:
chat_file.unlink()
Exception e:
()
__name__ == :
main()
Make executable:
chmod +x ~/scripts/claude_to_obsidian.py
6. Create Automation Script
Create ~/scripts/sync_claude_obsidian.sh:
#!/bin/bash
EXPORT_DIR="$HOME/claude-exports"
VAULT_DIR="$HOME/vault"
SCRIPT_DIR="$HOME/scripts"
LOG="$SCRIPT_DIR/sync.log"
echo "[$(date)] Sync started" >> "$LOG"
mkdir -p "$EXPORT_DIR/code" "$EXPORT_DIR/web"
claude-extract --all --output "$EXPORT_DIR/code" 2>> "$LOG"
python3 "$SCRIPT_DIR/claude_to_obsidian.py" \
--export-dir "$EXPORT_DIR" \
--vault-dir "$VAULT_DIR" \
--move 2>> "$LOG"
echo "[$(date)] Sync completed" >> "$LOG"
Make executable and schedule:
chmod +x ~/scripts/sync_claude_obsidian.sh
(crontab -l 2>/dev/null; echo "0 22 * * * $HOME/scripts/sync_claude_obsidian.sh") | crontab -
Using Graphify
Generate Knowledge Graph for a Project
Inside Claude Code:
/graphify . --obsidian --obsidian-dir ~/vault/graphify/my-project
From Terminal (AST-only mode, 0 tokens):
cd /path/to/project
graphify extract . --out ./graphify-out --no-cluster
With Semantic Extraction (uses LLM):
graphify extract . --out ./graphify-out --deep
graphify extract . --out ./graphify-out --deep --model claude-3-5-sonnet-20241022
Graphify Commands Reference
graphify extract <path> --out <output-dir>
graphify extract <path> --obsidian --obsidian-dir ~/vault/graphify/project-name
graphify extract <path> --out ./out --no-cluster
graphify extract <path> --out ./out --deep
graphify extract <path> --model claude-3-5-sonnet-20241022
graphify query <graph-dir> "find all auth functions"
Graph Output Structure
graphify-out/
├── graph.json # Full knowledge graph
├── nodes.json # Node index
├── edges.json # Edge index
└── obsidian/ # Obsidian-formatted notes (if --obsidian)
├── components/
├── functions/
└── relationships/
Workflow Patterns
Starting a New Session
/resume
This command makes Claude Code:
- Read the 3 most recent session logs
- Read
architecture/decisions.md for your project
- Summarize current state and pending work
Ending a Session
/save
This command makes Claude Code:
- Create a session log in
logs/YYYY-MM-DD-description.md
- Document completed work, decisions, and pending items
- Add wikilinks to created/modified notes
- Commit and push to git if in a repository
Creating Project Notes
Create a new note about our authentication flow in [[my-project/architecture/auth-flow]].
Include:
- OAuth provider integration
- Session management
- Token refresh strategy
Link to [[supabase-setup]] and [[api-design]].
Querying the Knowledge Graph
Query the Graphify graph for my-project:
- Find all functions that interact with the database
- Show dependencies for the auth module
- List unused utility functions
Updating the Graph
cd /path/to/project
/graphify . --obsidian --obsidian-dir ~/vault/graphify/my-project
Zettelkasten Best Practices
Atomic Notes
Good:
---
title: JWT Token Refresh Strategy
tags: [my-project, authentication, api]
created: 2024-01-15
updated: 2024-01-15
status: active
type: permanent
---
# JWT Token Refresh Strategy
## Context
We use sliding window refresh to minimize user disruption.
## Implementation
- Access token: 15 min expiry
- Refresh token: 7 day expiry
- Auto-refresh at 80% of access token lifetime
## Related
- [[authentication-flow]]
- [[supabase-auth-config]]
Bad (not atomic):
# Everything About Authentication
Contains JWT, OAuth, session management, password reset...
(Too many concepts in one note)
Dense Linking
Every permanent note should have at least 2 wikilinks to other notes. This creates the knowledge graph structure.
## Related
- [[parent-concept]]
- [[sibling-concept]]
- [[implementation-detail]]
Frontmatter Standards
---
title: Human Readable Title
tags: [project-name, topic, subtopic]
created: YYYY-MM-DD
updated: YYYY-MM-DD
status: active|draft|archived
type: permanent|fleeting|reference|chat
---
Troubleshooting
Graphify Skill Not Found
graphify install --platform claude
cat ~/.claude/skills/graphify/SKILL.md
API Key Issues
echo $ANTHROPIC_API_KEY
echo $MOONSHOT_API_KEY
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-3-5-sonnet-20241022",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Hello"}]
}'
Chat Import Not Working
claude-extract --help
chmod +x ~/scripts/claude_to_obsidian.py
chmod +x ~/scripts/sync_claude_obsidian.sh
~/scripts/sync_claude_obsidian.sh
tail -f ~/scripts/sync.log
Obsidian Wikilinks Not Resolving
- Ensure filenames are in kebab-case
- Check that wikilinks match exact filename without
.md
- Use relative paths for cross-folder links:
[[folder/note-name]]
- Verify YAML frontmatter is valid
Graph Query Returns Empty Results
ls ~/vault/graphify/my-project/
cat ~/vault/graphify/my-project/graph.json | head
graphify extract . --out ./out --verbose
Token Count Still High
Checklist:
- ✅ Generated Graphify graph for project
- ✅ CLAUDE.md exists in vault root
- ✅ Using
/resume and /save commands
- ✅ Session logs contain wikilinks to relevant notes
- ✅ Graph is up-to-date (re-run after major code changes)
Cron Job Not Running
sudo systemctl status cron
crontab -l
~/scripts/sync_claude_obsidian.sh
grep CRON /var/log/syslog
Configuration Examples
Multi-Project Setup
~/vault/
├── CLAUDE.md
├── project-a/
│ ├── architecture/
│ ├── features/
│ └── logs/
├── project-b/
│ ├── architecture/
│ ├── features/
│ └── logs/
└── graphify/
├── project-a/
└── project-b/
Custom Tag Mapping
Edit ~/scripts/claude_to_obsidian.py:
KEYWORD_TAG_MAP = {
"nextjs": "nextjs",
"tailwind": "tailwind",
"prisma": "prisma",
"vercel": "deploy",
"hook": "react-hooks",
"component": "components",
"util": "utilities",
"review": "code-review",
"optimize": "performance",
}
Graphify Model Selection
graphify extract . --model claude-3-haiku-20240307
graphify extract . --model claude-3-opus-20240229
graphify extract . --model claude-3-5-sonnet-20241022
Expected Results
- Initial session: ~20k tokens for codebase orientation
- With Graphify + Obsidian: ~280 tokens per session
- Reduction: 71.5x fewer tokens
- Memory persistence: 100% context retention across sessions
- Chat preservation: Zero conversation insights lost
Resources