Using OpenClaw's .openclaw folder as an Obsidian vault
OpenClaw stores everything in Markdown. Obsidian reads Markdown. So I made them the same folder — here's the architecture, the scripts, and what I learned.
The problem
I’ve been running OpenClaw on my server for a few months — it handles WhatsApp, Telegram, Discord conversations through a single AI agent. The thing I like about it is that everything is local. The agent’s personality (SOUL.md), its memory (MEMORY.md), daily logs, session transcripts — all Markdown and JSONL files sitting in ~/.openclaw/.
Separately, I use Obsidian for personal knowledge management. Notes, project tracking, references — the usual.
At some point I realized I was maintaining two knowledge systems that didn’t talk to each other. The AI would have a conversation about a project, build up context in its memory files, and none of that would show up in my Obsidian vault. I’d take notes about a topic, and the AI had no way to reference any of it.
The fix was obvious once I saw it: ~/.openclaw is already mostly a Markdown folder. Just make it the Obsidian vault.
What OpenClaw’s folder looks like
For context, here’s what OpenClaw creates on disk:
~/.openclaw/
├── workspace/
│ ├── SOUL.md # agent personality/tone
│ ├── MEMORY.md # curated long-term memory (~100 lines)
│ ├── USER.md # info about you
│ ├── IDENTITY.md # agent name/identity
│ ├── AGENTS.md # operating instructions
│ └── memory/
│ ├── 2026-02-22.md # daily memory log
│ ├── people/ # per-person context
│ ├── projects/ # per-project context
│ └── decisions/ # decision logs
├── agents/
│ └── <agentId>/sessions/
│ ├── sessions.json # session index
│ └── *.jsonl # raw transcripts
├── skills/
├── credentials/
└── openclaw.json
All the workspace/ files are plain Markdown. The agent reads and writes them at runtime. Session transcripts are JSONL — one JSON object per line with messages, metadata, token usage.
The architecture
Add Obsidian structure around the existing OpenClaw files without moving or renaming anything. OpenClaw keeps writing to its usual paths. A couple of scripts bridge the gap.
flowchart TB
subgraph inputs["Input channels"]
WA[WhatsApp]
TG[Telegram]
DC[Discord]
end
subgraph openclaw["OpenClaw runtime"]
SOUL[SOUL.md]
MEM[MEMORY.md]
DAILY[Daily memory logs]
JSONL[JSONL sessions]
end
subgraph bridge["Bridge scripts"]
CONV["convert-sessions.py\nJSONL → Markdown"]
INJ["inject-frontmatter.sh\nAdd YAML metadata"]
WATCH["inotifywait watcher\nsystemd service"]
end
subgraph obsidian["Obsidian layer"]
DASH[Dataview dashboards]
NOTES[Your notes / Zettelkasten]
SESS[Converted session notes]
MOCS[Maps of Content]
end
WA & TG & DC --> openclaw
JSONL --> CONV --> SESS
DAILY --> INJ
WATCH --> CONV
WATCH --> INJ
SOUL & MEM & SESS & NOTES --> DASH
NOTES & SESS --> MOCS
Three layers:
- OpenClaw native files — untouched, agent reads/writes them normally
- Bridge scripts — Python converts JSONL sessions to Markdown, shell script injects YAML frontmatter into workspace files so Dataview can query them
- Obsidian overlay — numbered folders for PARA + Zettelkasten, templates, Dataview dashboards
Vault structure
Number-prefixed folders so my stuff sorts above OpenClaw’s native directories:
~/.openclaw/ ← vault root
├── .obsidian/ ← obsidian config
├── 00-Dashboard/ ← dataview-powered dashboards
├── 01-Inbox/ ← fleeting captures
├── 02-Projects/ ← active projects (PARA)
├── 03-Areas/ ← ongoing domains
│ └── Career/ Health/ MLOps/ ...
├── 04-Resources/ ← books, articles, courses
├── 05-Zettelkasten/ ← atomic notes
├── 06-MOCs/ ← maps of content
├── 07-Archive/ ← done/inactive
├── 08-Templates/ ← note templates
├── 09-Sessions/ ← converted AI transcripts
│ └── 2026/02-Feb/
├── 10-Scripts/ ← automation
│
├── workspace/ ← openclaw native (untouched)
├── agents/ ← openclaw native
├── skills/ ← openclaw native
└── openclaw.json
Nothing fancy. 00-07 is a PARA-ish structure. 09-Sessions is where converted transcripts land. OpenClaw’s folders stay at the bottom.
The frontmatter schema
This is what makes cross-querying work. Every note — AI-generated or human — gets consistent YAML frontmatter:
---
created: 2026-02-22
type: session # session | zettel | project | soul | memory-daily | moc
source: openclaw # openclaw | human
tags: [session, telegram]
---
For sessions I also track channel, token counts, and cost:
agent: main
channel: telegram
tokens_in: 12450
tokens_out: 8920
cost: 0.032
session_id: abc123
The source field is how Dataview distinguishes “things the AI wrote” from “things I wrote.” The type field controls which dashboards pick up the note.
Converting sessions
OpenClaw stores conversations as JSONL. Each line is a message with role, content, timestamp, and usage metadata. The conversion script parses these into readable Markdown:
# core logic (simplified)
for line in jsonl_file:
entry = json.loads(line)
msg = entry.get("message", entry)
role = msg.get("role", "unknown")
content = extract_text(msg.get("content", ""))
emoji = {"user": "👤", "assistant": "🤖", "system": "⚙️"}[role]
messages.append(f"### {emoji} {role.title()} {time_str}\n\n{content}\n")
Output:
---
created: 2026-02-22
type: session
source: openclaw
channel: telegram
tokens_in: 12450
tokens_out: 8920
cost: 0.032
---
# Session — 2026-02-22 via Telegram
### 👤 User 14:32
Can you research Kubernetes security best practices?
---
### 🤖 Assistant 14:33
Based on the CIS benchmarks and recent CVEs...
## Key takeaways
-
## Links to vault notes
- [[]]
That “Links to vault notes” section is blank by default. When I review a session and spot something worth connecting, I add [[wikilinks]] to relevant project notes or concepts. This is the manual step that creates actual graph connections.
The script tracks converted files by hash so it’s safe to re-run. Output goes to 09-Sessions/YYYY/MM-Mon/.
Injecting frontmatter into workspace files
OpenClaw’s native Markdown files don’t have YAML frontmatter. A shell script adds it:
inject_if_missing() {
local file="$1" type="$2" tags="$3"
[ -f "$file" ] || return
head -1 "$file" | grep -q '^---$' && return # skip if exists
tmp=$(mktemp)
printf -- "---\ntype: %s\nsource: openclaw\ntags: [%s]\n---\n\n" \
"$type" "$tags" > "$tmp"
cat "$file" >> "$tmp"
mv "$tmp" "$file"
}
inject_if_missing "$WORKSPACE/SOUL.md" "soul" "ai-brain, soul"
inject_if_missing "$WORKSPACE/MEMORY.md" "memory-curated" "ai-brain, memory"
OpenClaw doesn’t care about the frontmatter — it treats --- blocks as regular text. Obsidian parses them as metadata. Both tools happy.
The file watcher
A systemd user service watches for changes and triggers conversions:
inotifywait -m -r \
-e create -e modify -e moved_to \
--include '.*\.(jsonl|md)$' \
"$OPENCLAW_DIR/agents/" \
"$OPENCLAW_DIR/workspace/" | while read -r directory event filename; do
if [[ "$filename" == *.jsonl ]]; then
sleep 2 # wait for write to finish
python3 convert-sessions.py
fi
if [[ "$directory" == *workspace/memory* ]]; then
bash inject-frontmatter.sh
fi
done
With debouncing. Cron runs every 15 minutes as fallback.
# ~/.config/systemd/user/openclaw-vault-sync.service
[Unit]
Description=OpenClaw Vault Sync Watcher
[Service]
Type=simple
ExecStart=/bin/bash ~/.openclaw/10-Scripts/watch-openclaw.sh
Restart=on-failure
[Install]
WantedBy=default.target
systemctl --user enable --now openclaw-vault-sync.service
Dataview dashboards
The home dashboard queries both AI and human content:
TABLE WITHOUT ID
file.link AS "Session",
channel AS "Channel",
tokens_out AS "Tokens Out",
cost AS "Cost ($)"
FROM "09-Sessions"
SORT created DESC
LIMIT 10
The AI Brain Dashboard shows the agent’s soul config, memory layers, people it knows about, project context, and session cost tracking. One page for everything the AI knows.
Daily notes embed the AI’s memory log using transclusion:
## AI activity today
> ![[2026-02-22#]]
My daily note shows what I did and what the AI did. Single record of the day.
The linking model
Three mechanisms connect AI content to human content:
flowchart LR
subgraph m1["Wikilinks in workspace files"]
A1[Edit MEMORY.md] --> A2["Add [[Project Name]] links"]
end
subgraph m2["Dataview queries"]
B1[Dashboards query both zones] --> B2[Tables show AI + human content]
end
subgraph m3["MOCs as indexes"]
C1[Maps of Content] --> C2["Reference workspace/ + vault notes"]
end
The most impactful one: editing MEMORY.md to include [[wikilinks]]. When the AI writes “working on the infrastructure migration,” I change it to “working on the [[Infrastructure Migration]]”. OpenClaw sees plain text. Obsidian sees a link. The graph grows.
What I’d change
Session summaries are manual. The conversion script doesn’t generate TL;DRs. Could pipe sessions through an LLM for auto-summaries, but reading through them and annotating is part of how I process things.
The JSONL format varies. OpenClaw’s session format isn’t formally documented, so the parser handles a few different structures depending on version. Lots of get("field", fallback) chains.
No mobile access. Vault lives on my server. I access via Syncthing to my laptop. No good mobile story yet.
Frontmatter injection is one-way. If OpenClaw rewrites a workspace file from scratch, the frontmatter gets blown away. The cron job re-injects it, but there’s a window where Dataview might miss it. Not a real problem in practice.
Setup
Packaged everything into a setup script:
git clone https://github.com/safoine/openclaw-obsidian-vault
cd openclaw-obsidian-vault
bash setup.sh
Then:
sudo apt install -y inotify-tools
bash ~/.openclaw/10-Scripts/inject-frontmatter.sh
python3 ~/.openclaw/10-Scripts/convert-sessions.py --force
systemctl --user enable --now openclaw-vault-sync.service
Open ~/.openclaw as a vault in Obsidian, install Dataview + Templater + Calendar + Periodic Notes, done.
Plugins needed
| Plugin | Why |
|---|---|
| Dataview | Powers every dashboard query |
| Templater | Template variables in notes |
| Calendar | Sidebar calendar for daily notes |
| Periodic Notes | Daily/weekly note creation |
| Obsidian Git | Optional, auto git backup |
Closing thoughts
The whole thing works because both tools operate on plain Markdown. No API integration, no sync service, no database bridge. Two tools reading and writing to the same folder, with a thin script layer to translate between JSONL and frontmattered Markdown.
The graph view after a few weeks is genuinely useful. Project notes connect to AI sessions. People notes link to what the AI remembers about them. Session notes link to the zettelkasten concepts they spawned.
If you’re running any local AI agent that writes to disk — the same approach applies. The scripts are OpenClaw-specific but the pattern is general: make the AI’s working directory your vault root, bridge the file formats, let Dataview do the rest.
Source code on GitHub — setup script, templates, dashboards, conversion scripts, systemd service.