reflect-markdown-mirror creates a one-way local Markdown cache from Reflect Notes data so local tools such as QMD can index and search your notes.
Reflect remains the source of truth. The generated Markdown folder is a disposable cache, not an editing target.
- Reads a copied snapshot of Reflect's local SQLite database, or a Reflect backup ZIP JSON export.
- Renders live notes to Markdown with frontmatter metadata.
- Moves root-level mirror files into
.state/deleted/when theirreflect_idis no longer present in the current live snapshot. In normal use, that means the note was deleted or is otherwise no longer live in Reflect. - Optionally runs collection-scoped
qmd updateandqmd embed. - Provides a scheduled-sync wrapper and read-only health check.
- It does not write back to Reflect.
- It does not edit Reflect's local database or OPFS files.
- It does not make the mirror safe to publish. Your generated mirror contains your private notes.
Use the Markdown mirror as a local retrieval/indexing cache, not as a collaboration surface:
- Sync Reflect into the mirror.
- Index the mirror with QMD.
- Use QMD to find relevant notes and snippets across the mirror.
- Read the note's
reflect_id,reflect_url, orreflect_deep_linkfrom the mirror frontmatter. - Use that note ID with Reflect MCP, or open the URL/deep link in Reflect, when you need source-of-truth context or edits.
Example mirrored frontmatter:
---
reflect_id: NOTE_ID
title: Example note
reflect_url: https://reflect.app/g/YOUR_GRAPH_ID/NOTE_ID
reflect_deep_link: reflect://reflect?command=edit-notes&id=NOTE_ID
---QMD is good for local lexical/semantic retrieval and citations over the generated files. Reflect MCP is the write/edit/source-of-truth interface. Do not edit mirrored Markdown and expect changes to sync back.
This repository is packaged as a small Python project so the CLI commands can be installed cleanly while developing:
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -e .
python -m unittest discover -s testspip install -e . installs the console commands from pyproject.toml in editable mode. You can also run the modules directly with PYTHONPATH=src python -m reflect_markdown_mirror.local_sync.
# Full local SQLite snapshot -> Markdown mirror dry run
reflect-markdown-mirror --source sqlite --graph-id YOUR_GRAPH_ID --mirror-dir ~/.local/share/reflect-markdown-mirror/mirror --dry-run --json
# Real sync, then QMD update/embed for the reflect collection
reflect-markdown-mirror --source sqlite --graph-id YOUR_GRAPH_ID --qmd-collection reflect --json
# Read-only health check
reflect-markdown-mirror-health --graph-id YOUR_GRAPH_ID --qmd-collection reflect --json--mirror-dir is the local folder where generated Markdown cache files are written. The default is ~/.local/share/reflect-markdown-mirror/mirror, but you can set it to any private local path. Do not point it at a Git repository or a folder you edit by hand.
If you omit --graph-id, the SQLite sync includes all live graph rows visible in the local database. You can also set REFLECT_GRAPH_ID in the environment.
qmd collection add ~/.local/share/reflect-markdown-mirror/mirror --name reflect
qmd context add qmd://reflect "Markdown mirror of Reflect notes. Reflect remains source of truth."
qmd update -c reflect
qmd embed -c reflectRoutine runs should stay collection-scoped, e.g. qmd embed -c reflect.
A practical handoff looks like this:
qmd search "distinctive phrase" -c reflect -n 5
qmd get "path-from-result.md" -c reflect -l 25Then copy reflect_id from the frontmatter and call Reflect MCP's get_note / edit tools with that ID. This was tested against a mirrored note: QMD found the note, qmd get exposed reflect_id and Reflect URLs in frontmatter, and MCP get_note resolved the same ID.
See examples/launchagents/com.example.reflect-markdown-mirror-sync.plist. Copy it to ~/Library/LaunchAgents/, replace placeholders, then load it with launchctl bootstrap.
The scheduled wrapper writes compact JSONL state under the mirror .state/ directory and can run a postflight health check. If you use a non-default mirror location, pass the same --mirror-dir and --state-dir to reflect-markdown-mirror-scheduled so sync, locking, health checks, and QMD all refer to the same cache.
Do not commit generated mirror output or Reflect source data:
- mirror Markdown files
.state/manifest.json.state/deleted/scheduled-sync.jsonl- Reflect SQLite files
- Reflect backup ZIPs or exports
- launchd logs
This repo is only for the service code, tests, examples, and docs.