Library / SDK
mfarragher/obsidiantools avatar
mfarragher/obsidiantools

obsidiantools: turning an Obsidian vault into a graph and a dataframe

Obsidian tools - a Python package for analysing an Obsidian.md vault

576 stars48 forksPythonNOASSERTION

At a glance

What is it?
obsidiantools is a Python package that reads an Obsidian.md vault and exposes it as a networkx graph, pandas dataframes and plain Python types, so note-taking data can be analysed with the usual scientific stack. It is built to support the shortest-path form of wikilinks and admits its parsing is uncertain outside Latin scripts.
Who is it for?
Adopt obsidiantools if you already keep notes in Obsidian and want to run graph analysis, text analysis or a dashboard over the vault from Python, since that is exactly what it does. Do not adopt it if you need a live view of the vault, because the documentation says the API features are no substitute for the interactivity of the Obsidian app.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 139 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Three lines of code produce the whole vault object

The pitch is that it is easy to explore structured data on your vault through a fluent interface, and the README shows the code needed to generate a vault object that stores all the data.

python
import obsidiantools.api as otools

vault = otools.Vault(<VAULT_DIRECTORY>).connect().gather()

That single chain is the whole entry point. The two method calls do the two halves of the work, and the README describes them as the basics of the method calls.

connect() connects your notes together in a graph structure and gets metadata on links, including wikilinks and backlinks, with the option to support the inclusion of attachment files in the graph. gather() gathers the plaintext content from your notes in one place, including the source text that represents how your notes are written, with arguments to support what text you want to remove, for example removing code.

The order matters and is not accidental. The graph has to exist before the text can be associated with nodes in it, and the README is explicit that gather() is a precondition for the source text and readable text accessors.

The primary language is Python, the package is published on PyPI, and the default branch is main. The recent releases are v0.11.0 from 2025-07-08, v0.10.0 from 2023-01-08 and v0.9.0 from 2022-12-24.

The graph is a networkx object, so the analysis stack is free

The first key feature is access to a networkx graph of your vault through vault.graph, and the README is explicit about why that matters. NetworkX is the main Python library for network analysis, enabling sophisticated analyses of your vault, and it also supports the ability to export your graph to other data formats.

That is the strategic decision in this package. Rather than inventing a graph abstraction, it hands you the one the Python ecosystem already uses, so the analysis you write is analysis you could have written against any other networkx graph, and the export path is standard.

The graph is filtered on instantiation. When you create a Vault, the analysis can also be filtered on specific subdirectories, which is how you get a graph of one project folder rather than the whole vault.

Two graph properties are called out because they answer the questions people actually ask of a vault. nonexistent_notes, nonexistent_media_files and nonexistent_canvas_files tell you whether files referenced as links actually exist, which catches broken links at scale. isolated_notes, isolated_media_files and isolated_canvas_files tell you whether actual files are isolated in the graph, which is the orphan check.

The main indices of files are md_file_index, media_file_index and canvas_file_index, and all the note and file links sit in one place, either as the whole-vault indexes such as vault.backlinks_index, or loaded for a single note with something like vault.get_backlinks(<NOTE>).

Three dataframes and the text extraction pipeline

The second feature is summary stats about notes and files in a Pandas dataframe, and there are three of them because Obsidian has three kinds of file. vault.get_note_metadata() covers notes and md files, vault.get_media_file_metadata() covers media files that can be embedded in notes, and vault.get_canvas_file_metadata() covers canvas files.

The per-note accessors cover the metadata that matters for analysis. Links come in four varieties, wikilinks including header links and links with alt text, embedded files, backlinks and markdown links. Front matter is available through vault.get_front_matter(<NOTE>) or the vault.front_matter_index, tags through vault.get_tags(<NOTE>) or vault.tags_index with nested tags supported, and LaTeX math through vault.get_math(<NOTE>) or vault.math_index.

The text handling is where the package earns its keep for language work, and the README describes the pipeline in one line: the text from vault notes goes through markdown, then split out front matter from text, then HTML, then ASCII plaintext. The two accessors reflect the two ends of that pipeline. get_source_text(<NOTE>) tries to represent how a note's text appears in Obsidian's source mode, and get_readable_text(<NOTE>) tries to reduce note text to minimal markdown formatting, preserving paragraphs, headers and punctuation, so that only slight processing is needed for various forms of NLP analysis.

The canvas file support is the newest-looking part. The JSON content of each canvas file is stored as a Python dict in vault.canvas_content_index, and the data to recreate the layout of content in a canvas file is held in the vault.canvas_graph_detail_index dict. That second one is notable, because it means a canvas, which is a spatial whiteboard format, can be treated as a graph in its own right rather than as opaque JSON.

Installing it, and the dependency set that explains the pipeline

Installation is a single command.

bash
`pip install obsidiantools`

Python 3.9 or higher is required.

The dependency list is short and every entry maps to a step of the processing pipeline. The main libraries are markdown and pymdown-extensions for the Markdown stage, html2text for the HTML to ASCII stage, pandas and numpy for the dataframe layer, and networkx for the graph.

The front matter and HTML libraries are python-frontmatter, beautifulsoup4, lxml and bleach. The README explains why all of these are needed: so that the package can separate note text from front matter in a generalised approach.

That last point is the design driver. Rather than special-casing the YAML block at the top of a note, the package converts the note to HTML and then separates the front matter from the body, which works for notes whose front matter is unconventional or whose body contains things that look like front matter. The cost is that it is a heavier pipeline than a line of YAML parsing, and bleach is there because the HTML passes through a sanitiser on the way.

The setup.py declares the same dependencies in a single install_requires list, sets python_requires to 3.9, and marks the project as Development Status 3 - Alpha with an intended audience of Education and Science/Research.

The shortest path assumption, and the language caveat

Two limitations are stated in the README and both matter in practice.

The first is the link syntax. The package is built to support the shortest path when possible option for links, and the README says this should cover the vast majority of vaults that people create. The wiki is the place to check what sort of wikilink syntax is not well-supported and how the graph may be slightly different to what you see in the Obsidian app.

That is a meaningful caveat for anyone with an unusual vault, because the graph and the link counts are the products here. If a note uses a path-qualified link where the shortest form would resolve differently, the connectivity you get will not match the app, and everything downstream of the graph inherits the difference.

The second is language. The author says plainly that he is not sure how the parsing will work outside of Latin languages, and invites ideas on how that can be supported as a feature or pull request.

That caveat is worth taking seriously for a package whose text pipeline is markdown, then front matter separation, then HTML, then ASCII plaintext. Each of those stages involves tokenising and, at the HTML stage, an implicit assumption about word boundaries that ASCII plaintext conversion is designed around. A vault in Chinese, Japanese or Thai, where there are no spaces between words, is exactly the case where the final stage can lose information.

The test approach is disclosed too. There is a small dummy vault of lipsum notes in tests/vault-stub, generated with the help of the lorem-markdownum tool, and sense-checking on the API functionality was also done on a personal vault of over 800 notes.

What obsidiantools is not, and where the alternative sits

The honest framing is that this is a data extraction and analysis library, not a note-taking application, and the README says so in one sentence: there are other API features that try to mirror the Obsidian.md app for convenience when working with Python, but they are no substitute for the interactivity of the app.

That boundary is the whole design. The library reads a vault as it exists on disk, so it sees the files, not the application state. It has no editor, no plugin, no sync, and no live view. If your question is how your notes connect, this is the right tool. If your question is what I am looking at right now, it is not.

The realistic alternatives fall into two groups. The first is the Obsidian community plugins and the Dataview-style query engines, which run inside the application and give you queries over the vault without leaving it. Their advantage is that they see exactly what the app sees, so the shortest-path ambiguity disappears. Their limitation is that they are tied to the app and to a query language rather than to Python, and they are hard to use for anything that needs a real networkx graph or a pandas pipeline.

The second group is doing it yourself with the markdown and frontmatter libraries directly. That is what obsidiantools is, packaged, with the Obsidian-specific link semantics, the canvas handling, the nonexistent-link and orphan checks, and the source and readable text views. If your notes use plain wikilinks and you want a graph plus dataframes, the package saves you from writing the link resolution and the text normalisation yourself.

One more limitation to keep in view. The repository licence field shows a custom licence GitHub cannot classify, while the README states Modified BSD (3-clause) and the badge and setup.py classifier both say BSD. Read the LICENSE file before redistributing anything built on it, because a modified BSD with additional terms is not the same thing as stock BSD-3-Clause.

The last push was on 2026-06-07 and the newest release is from July 2025, so the code moves and the tags do not.

Editorial conclusion

Adopt obsidiantools if you already keep notes in Obsidian and want to run graph analysis, text analysis or a dashboard over the vault from Python, since that is exactly what it does. Do not adopt it if you need a live view of the vault, because the documentation says the API features are no substitute for the interactivity of the Obsidian app. Before you rely on the numbers, check the wikilink syntax your vault actually uses against the project wiki, and note the last push was on 2026-06-07 with release v0.11.0 from 2025-07-08.

Frequently asked questions

How do I load an Obsidian vault with obsidiantools?

Create a Vault with your vault directory, then chain connect() and gather(). connect() builds the graph of your notes and gathers link metadata such as wikilinks and backlinks, and gather() collects the plaintext content of the notes.

What can I get out of an Obsidian vault with obsidiantools?

A networkx graph through vault.graph, pandas dataframes through get_note_metadata(), get_media_file_metadata() and get_canvas_file_metadata(), and per-note detail as built-in types, including front matter, tags with nested tags supported, LaTeX math, source text and readable text.

What dependencies does obsidiantools need?

markdown, pymdown-extensions, html2text, pandas, numpy, networkx, plus python-frontmatter, beautifulsoup4, bleach and lxml for front matter and HTML handling. They are all needed so the package can separate note text from front matter in a generalised approach.

Does obsidiantools work with non-Latin languages?

That is not known. The author states he is not sure how the parsing will work outside of Latin languages and invites ideas on how to support it, since the text pipeline goes through markdown, front matter separation, HTML and finally ASCII plaintext.

How do I find broken links and orphan notes in my vault?

The vault object exposes nonexistent_notes, nonexistent_media_files and nonexistent_canvas_files for links that point at files which do not exist, and isolated_notes, isolated_media_files and isolated_canvas_files for real files that are not connected in the graph.

Official sources

  1. Issues
  2. mfarragher/obsidiantools on GitHub
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mfarragher-obsidiantools.svg)](https://hysenlabs.com/projects/mfarragher-obsidiantools)

Was this useful?