Repository navigation
feat(export): add --with-sources to wire Obsidian notes to source content (#1968) - #1973
SinghAman21 wants to merge 3 commits into
Conversation
|
@safishamsi it will be great if you could review this, else PR will become stale and conflicts would occur thanks. |
nothariharan
left a comment
There was a problem hiding this comment.
The feature works. I ran it end to end on a scratch project: graphify export obsidian --with-sources copies each source under sources/, markdown goes in verbatim, code goes in a fenced block with the right language hint, and every node note gets a > [!info] Source callout under the H1 with the original path as the alias. Re-exporting without the flag prunes the source notes and strips the callouts, so the manifest ownership behaviour holds. 439 existing export tests plus your 5 new ones pass on current v8.
Two asks:
1. CHANGELOG lands in the wrong section. The diff adds the entry under ## 0.9.18 (2026-07-17), which is already released. It needs to move to the current unreleased heading, otherwise it ships inside an old version's notes.
2. _resolve_source_path follows .. and absolute paths. Since source_file can hold an absolute path for a file outside the scan root, and the join is unclamped, I confirmed that a node with source_file="../secret.txt" results in that file's contents being embedded into the vault. Given the arbitrary-read hardening already in the Fortran extractor (GHSA-pcc4-rvhr-2pr8), I would clamp resolution to the scan root and skip anything that escapes it. It is opt-in so not urgent, but it is the kind of thing a reviewer here will always ask about.
Neither changes the design, which I like. Graphify-owned notes mean the existing prune machinery cleans up after the flag for free, and a re-export without the flag genuinely returns the vault to plain notes. The 2 MB cap and the no-callout-rather-than-dangling-link choice are both the right call.
cd8550c to
3f9179e
Compare
…bs#1968) Resolve source paths before copying and require the canonical path to remain beneath a selected scan root. This rejects traversal paths and symlinks that escape the scan tree. Add a regression test and record the feature under the current changelog section.
3f9179e to
3fe5828
Compare
Reject source_file values that resolve outside the configured scan root, including absolute paths.

Wire Obsidian node notes to their source content (--with-sources) — #1968
Why
Right now every note in an exported Obsidian vault is a bare stub: frontmatter, the H1 title, and a ## Connections list of wikilinks. The source_file field exists in frontmatter but it's just a dead string — it doesn't link to anything. So anyone browsing the vault (or an agent hopping between notes) has to leave the vault entirely to learn what a node actually is. The graph structure is great, but the notes carry no substance.
Users were working around this with a post-processing script that copies sources in and rewires every note — but the exporter overwrites the notes on each re-export, so they had to re-run the script every single time.
What
A new opt-in flag on the Obsidian export:
graphify export obsidian --with-sources
With it, the vault becomes usable standalone:
How
Behavior chosen deliberately:
Conclusion
This solves the issue's core ask — turn source_file into a resolvable link and bring source content into the vault — without any manual post-processing. It's fully opt-in, so default exports are unchanged, and it plays cleanly with the existing re-export/prune machinery. Covered by a new test file (tests/test_obsidian_with_sources.py, 5 tests) with the existing export suite (91 tests) still green.