Obsidian Vault Writer — Cross-Agent Integration Handoff
**Date**: 2026-03-01 **Author**: Claude Code (Opus 4.6) **For**: All agent sessions (Codex, Gemini, Clawdbot, Cursor, future agents) **Status**: Phase 1-4 complete, live on cloud-vm
Full Public Reader
Obsidian Vault Writer — Cross-Agent Integration Handoff
Date: 2026-03-01
Author: Claude Code (Opus 4.6)
For: All agent sessions (Codex, Gemini, Clawdbot, Cursor, future agents)
Status: Phase 1-4 complete, live on cloud-vm
---
What This Is
The Obsidian Vault Writer is a Python module that writes structured Markdown notes to an Obsidian vault. Every note has YAML frontmatter and `[[bidirectional links]]` that create an organic knowledge graph. The vault lives on cloud-vm and syncs to all devices via Obsidian Sync (E2E encrypted).
The core idea: Every agent session, every Discord synthesis, every AAO task completion, and every Prefect flow run should produce a vault note. Over time, `[[backlinks]]` reveal connections between ideas, projects, and agents that no single system tracks.
---
File Locations
Vault Writer Module
[home-path]
├── __init__.py # Package init, version 0.1.0
├── config.py # VAULT_PATH, directory names, filter lists
├── slugify.py # Unicode title → filesystem-safe slug
├── templates.py # Markdown templates for 8 note types
├── linker.py # [[wikilink]] extraction from synthesis JSON
├── writer.py # VaultWriter class + CLI entry point (4 modes)
├── backfill.py # One-time kimi_memory.db migration
├── requirements.txt # pyyaml>=6.0
├── ARCHITECTURE.md # Full architecture documentation
└── INTEGRATION-HANDOFF.md # This fileVault Directory (cloud-vm + synced to all devices)
[home-path]
├── Inbox/ # Real-time synthesis notes, by date
│ └── YYYY-MM-DD/
│ └── {HHMMSS}-{slug}.md
├── Projects/ # One note per project (evergreen index)
├── Entities/ # One note per knowledge graph entity
├── Concepts/ # Dream seed ideas
├── Sessions/ # Agent session summaries (ALL agent types)
├── Daily/ # Auto-generated daily rollups
├── Knowledge/ # Curated: Facts.md, Preferences.md, Patterns.md
└── Templates/ # 5 Obsidian templatesIntegration Points (files that call the vault writer)
| File | Location | Trigger | What it writes |
|---|---|---|---|
| `synthesis-preprocessor.js` | `[home-path]` | Discord message synthesized | `Inbox/{date}/{time}-{slug}.md` |
| `session_end_hook.py` | `[home-path]` | Claude Code session ends | `Sessions/{date}-claudecode-{id}.md` |
| `aao_reputation_collector.py` | `[home-path]` | AAO task quality assessed | `Sessions/{date}-{agenttype}-{task_id}.md` |
| `vault_sync.py` | `[home-path]` | Every 6h Prefect flow | Catch-up synthesis + agent sessions + daily summaries |
Infrastructure
| Component | Location | Port | Role |
|---|---|---|---|
| obsidian-sync.service | cloud-vm systemd | — | Continuous vault sync via `ob sync --continuous` |
| obsidian-headless (ob) | `/usr/bin/ob` on cloud-vm | — | Node 22+ CLI for headless Obsidian |
| Obsidian Cloud | Agent Vault (North America) | — | E2E encrypted sync hub |
---
How To Write a Vault Note (For Any Agent)
Method 1: Subprocess (fire-and-forget, recommended for hooks/daemons)
echo '{"agent_type":"codex","session_id":"xyz-123","provider":"openai","model":"o3-mini","goal":"Fix auth bug","outcome":"complete","date":"2026-03-01","stats":{"duration_minutes":12.5,"prompt_count":5,"tool_call_count":30,"files_modified":["auth.py","config.py"],"files_read":["models.py"],"aao_quality":"high","aao_confidence":0.9,"aao_device_score":0.88},"project_refs":["comp-core"],"key_topics":["authentication"],"source":"codex-daemon"}' \
| python3 -m obsidian_vault_writer.writer --mode agent-sessionEnvironment: Set `VAULT_PATH` env var (defaults to `[home-path]`).
Working directory: Must be `[home-path]` (so Python can find the package).
Method 2: Python import (for Prefect flows or Python scripts)
import sys
sys.path.insert(0, str(Path.home() / "projects"))
from obsidian_vault_writer.writer import VaultWriter
writer = VaultWriter() # Uses VAULT_PATH env or [home-path]
# Agent session note
path = writer.write_agent_session({
"agent_type": "gemini", # claude-code | codex | gemini | clawdbot | human | custom
"session_id": "abc-123",
"provider": "google", # anthropic | openai | google | together
"model": "gemini-2.5-pro",
"goal": "Research N'Ko morphology",
"outcome": "complete", # complete | failed | cancelled | interrupted | degraded
"date": "2026-03-01",
"stats": {
"duration_minutes": 25.0,
"prompt_count": 8,
"tool_call_count": 15,
"files_modified": ["research.md"],
"files_read": ["corpus.txt"],
# Optional AAO fields (if task was AAO-gated):
"aao_quality": "high", # high | medium | low | failed
"aao_confidence": 0.85,
"aao_device_score": 0.91,
},
"project_refs": ["nko-linguistics"], # Creates [[project]] links + Project stubs
"key_topics": ["morphology", "NKo"], # Creates [[topic]] links
"source": "gemini-daemon",
})
print(f"Written: {path}")
# → [home-path]Method 3: Synthesis note (for Discord/chat synthesis)
path = writer.write_synthesis(
synthesis={
"enriched_prompt": "Full context-enriched prompt...",
"intent": "idea",
"confidence": 0.85,
"route": "direct",
"dream_seeds": [{"title": "Voice NKo Keyboard", "energy": 0.7, "tags": ["NKo"]}],
"skill_chain": ["lin:nko", "thk:quantum"],
"knowledge_connections": [
{"subject": "NKo keyboard", "predicate": "related_to", "object": "voice recognition"}
],
"learnings": {"facts": [{"key": "nko_voice", "value": "requires tone-aware recognition"}]},
"project_refs": ["nko-linguistics"],
},
message="Original user message text",
channel="discord:ideas",
)---
Universal Agent Session Schema
Every agent session note follows this JSON schema:
{
"agent_type": "claude-code",
"session_id": "unique-session-id",
"provider": "anthropic",
"model": "claude-opus-4-6",
"goal": "What was being worked on (first 120 chars)",
"outcome": "complete",
"date": "2026-03-01",
"stats": {
"duration_minutes": 45.3,
"prompt_count": 12,
"tool_call_count": 87,
"files_modified": ["file1.py", "file2.rs"],
"files_read": ["config.py"],
"estimated_tokens": 15000,
"aao_quality": "high",
"aao_confidence": 0.85,
"aao_device_score": 0.912
},
"project_refs": ["comp-core", "nko-linguistics"],
"key_topics": ["authentication", "graph-kernel"],
"source": "session_end_hook"
}Agent Types
| `agent_type` | Provider | Source |
|---|---|---|
| `claude-code` | `anthropic` | SessionEnd hook, prompt-log scanner, AAO |
| `codex` | `openai` | Manual stdin, AAO task with model_used containing "gpt"/"o1"/"o3" |
| `gemini` | `google` | Manual stdin, AAO task with model_used containing "gemini" |
| `clawdbot` | varies | Manual stdin, gateway-originated tasks |
| `human` | — | Manual entry for human-performed tasks |
| `custom` | varies | Fallback for unrecognized agent types |
Sources
| `source` value | Meaning |
|---|---|
| `session_end_hook` | Claude Code SessionEnd hook (real-time, fire-and-forget) |
| `prompt_scan` | Prefect vault_sync scan of `[home-path]` (catch-up) |
| `aao-reputation:discord` | AAO reputation collector after task quality assessment |
| `aao-reputation:sms` | Same, task originated from SMS gateway |
| `cap` | Future: Clarity Agent Protocol dispatcher |
| `manual` | Manual CLI invocation |
---
What Gets Generated (Note Format)
Agent Session Note → `Sessions/{date}-{agenttype}-{short_id}.md`
---
type: agent-session
agent_type: claude-code
provider: anthropic
model: claude-opus-4-6
session_id: abc123def456
date: 2026-03-01
outcome: complete
source: session_end_hook
duration_minutes: 45.3
prompt_count: 12
tool_calls: 87
aao_quality: high
aao_confidence: 0.85
aao_device_score: 0.912
project_refs: [comp-core]
tags: [authentication, graph-kernel]
created: 2026-03-01T18:30:00Z
---
# Claude Code Session: Fix authentication bug in login flow
| | |
|---|---|
| **Agent** | Claude Code (claude-opus-4-6) |
| **Duration** | 45m |
| **Prompts** | 12 |
| **Tool Calls** | 87 |
| **Outcome** | complete |
| **AAO Quality** | high (85% confidence) |
| **Device Score** | 0.91 |
## Goal
Fix authentication bug in login flow
## Files Modified (2)
- `auth.py`
- `config.py`
## Files Read (1)
- `models.py`
## Links
- Project: [[comp-core]]
- Related: [[authentication]]
- Related: [[graph-kernel]]Synthesis Note → `Inbox/{date}/{time}-{slug}.md`
---
type: synthesis
intent: idea
confidence: 0.85
route: direct
channel: discord
project_refs: [nko-linguistics]
tags: [NKo, voice-recognition]
created: 2026-03-01T10:30:00Z
---
# Voice-Controlled NKo Keyboard
## Enriched Prompt
Context-rich synthesis...
## Dream Seeds
- **Voice-Controlled NKo Keyboard** (energy: 0.7)
Tags: NKo, voice recognition
## Knowledge Connections
- [[NKo keyboard]] --related to--> [[voice recognition]]
## Links
- Project: [[nko-linguistics]]
- Related: [[NKo keyboard]], [[voice recognition]]---
AAO → Vault Integration (The Loop)
The AAO (Admissible Agent Orchestration) reputation collector closes the loop between task execution and knowledge capture.
Flow
Discord/SMS/Telegram task
↓
mac_tasks row created in Supabase
↓
AAO Ticket Gate (mints HMAC token, every 3min)
↓
AAO Dedup Filter (fingerprints, blocks duplicates, every 5min)
↓
pulse-dispatcher (claims + routes to device)
↓
Agent executes on device (Mac1-5, cloud-vm)
↓
Task completes → mac_tasks.status = 'complete'
↓
AAO Reputation Collector (every 10min)
├── Assess quality (output length, exit code, errors, duration)
├── Sign HMAC attestation → Graph Kernel
├── Update device reputation score
└── write_task_to_vault() ← NEW
├── Map claimed_by → agent_type
├── Infer provider from model_used
├── Extract project_refs from project_path
├── Include aao_quality, aao_confidence, aao_device_score
└── Sessions/{date}-{agenttype}-{task_uuid}.md
↓
obsidian-sync → all devicesSupabase Fields Used
SELECT id, task_content, output, exit_code, duration_ms, error_log,
claimed_by, completed_at, started_at, task_type, model_used,
project_path, source, session_id, pool_mode, team_role
FROM mac_tasks
WHERE status = 'complete' AND completed_at > $last_assessed_at
ORDER BY completed_at DESC LIMIT 30Agent Type Detection
# Priority 1: Model string override
if "gpt" or "o1" or "o3" in model_used → agent_type = "codex"
if "gemini" in model_used → agent_type = "gemini"
# Priority 2: Device mapping
claimed_by = "mac1" through "mac5" → agent_type = "claude-code"
claimed_by = "cloud-vm" → agent_type = "claude-code"
claimed_by = "codex" → agent_type = "codex"
# Fallback
else → agent_type = "custom"---
Nexus Portal Integration Opportunities
The Nexus Portal (`[home-path]`, port :3001) already has a "Vault" page that shows Discord content performance. The vault writer creates a richer dataset.
Current State
| Nexus Page | Data Source | Vault Connection |
|---|---|---|
| Overview | Dashboard API + Prometheus | Could show vault note count, today's sessions |
| Agents | Supabase mac_tasks, mesh_devices | Agent sessions are now vault notes with AAO quality |
| Flows | Prefect API | vault_sync is a registered flow, shows run history |
| Feeds | Prefect API (tag:feed-hub) | Synthesis notes from feeds now land in vault |
| Vault (existing) | Supabase content_performance | Discord engagement stats — separate from knowledge vault |
| Evolution | Dashboard API /api/hef/* | Evolved ideas could become vault Concepts |
Integration Points for Nexus
1. New API endpoint: `GET /api/vault/stats` on Dashboard API → returns note counts by directory, recent notes, orphan count. Nexus Overview page could show a "Knowledge Vault" card.
2. Agent page enrichment: Each agent in the Agents page already shows tasks from mac_tasks. Link to the corresponding vault session note (same task UUID).
3. Flow page enrichment: The vault_sync flow runs appear in the Flows page. Could add a "Vault Health" section showing: notes created this run, catch-up count, daily summary status.
---
Prefect Flow Integration Opportunities
Currently Connected
| Flow | File | Vault Integration |
|---|---|---|
| `vault-sync` | `[home-path]` | Primary: catch-up writes, agent session scanner, daily summaries, orphan detection |
| `aao-reputation-collector` | `[home-path]` | Active: writes vault note per assessed task |
Ready for Integration
| Flow | File | Potential |
|---|---|---|
| `morning-brief` | `[home-path]` | Append flow stats, task counts, dream counts to `Daily/{date}.md` |
| `garden-tender` | `[home-path]` | Auto-create `Concepts/{dream_title}.md` when dreams emerge from Noosphere |
| `dream-chronicle` | `[home-path]` | Track dream lifecycle (gestating → emerging → emerged) as vault notes |
| `memory-summarizer` | `[home-path]` | Write `Knowledge/` updates from curated memory turns |
| `creative-chronicle` | `[home-path]` | Track content series progress as vault notes |
| `engagement-collector` | `[home-path]` | Write `Daily/{date}.md` with top-performing content |
| HEF evolution | `[home-path]` | Archive completed evolutions as vault `Concepts/` or `Projects/` notes |
How To Add Vault Write to Any Flow
# At top of flow file
import sys
from pathlib import Path
VAULT_WRITER_DIR = Path.home() / "projects"
if str(VAULT_WRITER_DIR) not in sys.path:
sys.path.insert(0, str(VAULT_WRITER_DIR))
# In your task function
from obsidian_vault_writer.writer import VaultWriter
writer = VaultWriter()
path = writer.write_agent_session({...}) # or write_synthesis(), write_daily_summary()---
Database Integration Points
Supabase Tables → Vault
| Table | Current Vault Use | Potential |
|---|---|---|
| `mac_tasks` | AAO reputation collector reads completed tasks → vault session notes | Full task lifecycle tracking |
| `synthesis_results` | vault_sync catch-up reads missing rows → Inbox notes | Real-time webhook trigger |
| `noosphere_dreams` | Not yet connected | Dream lifecycle vault notes |
| `content_performance` | Not yet connected | Daily engagement highlights |
| `memory_turns` | Not yet connected | Memory consolidation vault notes |
| `pulse_sessions` | Not yet connected | Pulse session summaries → Sessions/ |
| `reputation_attestations` | Written by AAO reputation collector | Device reputation trends in vault |
| `knowledge_graph` | Backfilled once (5,562 → 195 triples → 53 entity notes) | Periodic re-sync possible |
Graph Kernel (Rust, port :8001)
The Graph Kernel stores semantic triples and AAO attestations. Integration:
- AAO attestations already registered via `POST /api/knowledge/attestation`
- Vault entity notes could be enriched with Graph Kernel relation counts
- Future: Graph Kernel query → verify vault entity completeness
Orbit / RAG++ (port :3847 local, Cloud Run)
The SessionEnd hook already notifies Orbit (`/api/rag/session-end`). Vault notes and Orbit embeddings are complementary:
- Orbit provides semantic search across session content
- Vault provides navigable `[[linked]]` knowledge graph
- Context recovery MCP (`get_context_recovery`) reads from Orbit — could also read vault note frontmatter
---
Sync Architecture
Source Systems
┌─────────────────────────────────────────────┐
│ Discord Claude Code AAO Tasks Prefect│
│ Synthesis SessionEnd Reputation Flows │
└──────┬──────────┬───────────┬──────────┬─────┘
│ │ │ │
▼ ▼ ▼ ▼
┌──────────────────────────────────────────────┐
│ obsidian_vault_writer (Python module) │
│ │
│ write_synthesis() write_agent_session() │
│ write_daily_summary() ensure_entity() │
│ ensure_project() ensure_concept() │
└───────────────────┬──────────────────────────┘
│ writes .md files
▼
┌──────────────────────────────────────────────┐
│ [home-path] (cloud-vm filesystem) │
│ │
│ Syncthing ←→ Mac1 │
│ ob sync --continuous → Obsidian Cloud │
└───────────────────┬──────────────────────────┘
│ Obsidian Sync (E2E)
┌────────────┼────────────┐
▼ ▼ ▼
iPhone Mac4/Mac5 Any device
Obsidian Obsidian with Obsidian---
For Agents: Quick Start
If you're a Codex/Gemini/Clawdbot agent completing a task:
# Pipe your session data to the vault writer
echo '{"agent_type":"YOUR_TYPE","session_id":"YOUR_SESSION","provider":"YOUR_PROVIDER","model":"YOUR_MODEL","goal":"What you worked on","outcome":"complete","date":"'$(date +%Y-%m-%d)'","stats":{"duration_minutes":10,"prompt_count":5,"tool_call_count":20,"files_modified":["file.py"],"files_read":["config.py"]},"project_refs":["project-name"],"key_topics":["topic"],"source":"YOUR_SOURCE"}' \
| python3 -m obsidian_vault_writer.writer --mode agent-sessionIf you're adding vault writes to a Prefect flow:
1. Import VaultWriter at the top of your flow file
2. Call the appropriate write method in your task function
3. Always use fire-and-forget — vault writes should never block flow execution
4. Set `VAULT_PATH` env var if not using the default `[home-path]`
If you're building a new integration:
1. Read `[home-path]` for full details
2. The universal agent session schema (above) is the contract — follow it
3. Add your `agent_type` to the template's `agent_label` dict in `templates.py` if you want a custom display name
4. Your notes will automatically get `[[backlinks]]` from project stubs and entity stubs
---
Current Statistics (2026-03-01)
| Directory | Count | Primary Source |
|---|---|---|
| Inbox/ | 4 | Backfilled synthesis results |
| Entities/ | 75 | 53 knowledge graph + 22 synthesis link stubs |
| Projects/ | 4 | comp-core, nko-linguistics, litRPG, milkmen |
| Concepts/ | 3 | Dream seeds from synthesis |
| Knowledge/ | 3 | Facts, Preferences, Patterns indexes |
| Sessions/ | 0 | First real notes will appear when sessions end + AAO tasks complete |
| Daily/ | 0 | First daily summary on next vault_sync run |
| Templates/ | 5 | Synthesis, Session, Entity, Project, Daily |
| Total | 94 |
---
Key Design Principles
1. Never block: All vault writes are fire-and-forget. Use `subprocess.Popen()` without `wait()`, or `spawn()` + `unref()` in Node.js.
2. Belt and suspenders: Real-time hooks catch 99
3. Idempotent stubs: `ensure_entity()`, `ensure_project()`, `ensure_concept()` are no-ops if the note already exists.
4. Universal schema: One JSON format for all agent types. Agent-specific metadata goes in the `stats` dict.
5. Obsidian-native: Every note has YAML frontmatter for Dataview queries and `[[wikilinks]]` for graph navigation.
Promotion Decision
Attach run IDs, datasets, metrics, and reproduction commands.
Source Anchor
projects/obsidian_vault_writer/INTEGRATION-HANDOFF.md
Detected Structure
Method · Evaluation · References · Code Anchors · Architecture