{"id":13910629,"url":"https://github.com/natelandau/obsidian-metadata","last_synced_at":"2025-09-30T20:31:50.713Z","repository":{"id":65418939,"uuid":"580104460","full_name":"natelandau/obsidian-metadata","owner":"natelandau","description":"Batch updates to metadata in an Obsidian vault","archived":true,"fork":false,"pushed_at":"2024-04-01T09:25:16.000Z","size":822,"stargazers_count":147,"open_issues_count":13,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-09-06T20:31:16.503Z","etag":null,"topics":["obsidian","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/natelandau.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-19T18:22:03.000Z","updated_at":"2025-08-25T04:28:37.000Z","dependencies_parsed_at":"2023-12-19T18:25:58.455Z","dependency_job_id":"0d126cea-08df-4cd5-8a73-a6e1d219e4e8","html_url":"https://github.com/natelandau/obsidian-metadata","commit_stats":{"total_commits":61,"total_committers":3,"mean_commits":"20.333333333333332","dds":0.2295081967213115,"last_synced_commit":"d636fb2672639d64cb0b54dada5d212d77dfd6dc"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/natelandau/obsidian-metadata","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/natelandau%2Fobsidian-metadata","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/natelandau%2Fobsidian-metadata/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/natelandau%2Fobsidian-metadata/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/natelandau%2Fobsidian-metadata/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/natelandau","download_url":"https://codeload.github.com/natelandau/obsidian-metadata/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/natelandau%2Fobsidian-metadata/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274039529,"owners_count":25211901,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-07T02:00:09.463Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["obsidian","python"],"created_at":"2024-08-07T00:01:39.061Z","updated_at":"2025-09-30T20:31:50.406Z","avatar_url":"https://github.com/natelandau.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"[![PyPI version](https://badge.fury.io/py/obsidian-metadata.svg)](https://badge.fury.io/py/obsidian-metadata) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/obsidian-metadata) [![Python Code Checker](https://github.com/natelandau/obsidian-metadata/actions/workflows/automated-tests.yml/badge.svg)](https://github.com/natelandau/obsidian-metadata/actions/workflows/automated-tests.yml) [![codecov](https://codecov.io/gh/natelandau/obsidian-metadata/branch/main/graph/badge.svg?token=3F2R43SSX4)](https://codecov.io/gh/natelandau/obsidian-metadata)\n\n# obsidian-metadata\n\nA script to make batch updates to metadata in an Obsidian vault. No changes are\nmade to the Vault until they are explicitly committed.\n\n[![asciicast](https://asciinema.org/a/DQk0ufza1azwU3QFkE6XV33nm.svg)](https://asciinema.org/a/DQk0ufza1azwU3QFkE6XV33nm)\n\n## Important Disclaimer\n\n**It is strongly recommended that you back up your vault prior to committing changes.** This script makes changes directly to the markdown files in your vault. Once the changes are committed, there is no ability to recreate the original information unless you have a backup. Follow the instructions in the script to create a backup of your vault if needed. The author of this script is not responsible for any data loss that may occur. Use at your own risk.\n\n## Install\n\nRequires Python v3.10 or above.\n\n```bash\npip install obsidian-metadata\n```\n\n## Usage\n\n### CLI Commands\n\n-   `--config-file`: Specify a custom configuration file location\n-   `--dry-run`: Make no destructive changes\n-   `--import-csv` Import a CSV file with bulk updates\n-   `--export-csv`: Specify a path and create a CSV export of all metadata\n-   `--export-json`: Specify a path and create a JSON export of all metadata\n-   `--export-template`: Specify a path and export all notes with their associated metadata to a CSV file for use as a bulk import template\n-   `--help`: Shows interactive help and exits\n-   `--log-file`: Specify a log file location\n-   `--log-to-file`: Will log to a file\n-   `--vault-path`: Specify a path to an Obsidian Vault\n-   `--verbose`: Set verbosity level (0=WARN, 1=INFO, 2=DEBUG, 3=TRACE)\n-   `--version`: Prints the version number and exits\n\n### Running the script\n\nOnce installed, run `obsidian-metadata` in your terminal to enter an interactive menu of sub-commands.\n\n**Vault Actions**\n\n-   Backup: Create a backup of the vault.\n-   Delete Backup: Delete a backup of the vault.\n\n**Export Metadata**\n\n-   Export all metadata to a CSV organized by metadata type\n-   Export all metadata to a CSV organized by note path\n-   Export all metadata to a JSON file organized by metadata type\n\n**Inspect Metadata**\n\n-   **View all metadata in the vault**\n-   View all **frontmatter**\n-   View all **inline metadata**\n-   View all **inline tags**\n\n**Filter Notes in Scope**: Limit the scope of notes to be processed with one or more filters.\n\n-   **Path filter (regex)**: Limit scope based on the path or filename\n-   **Metadata filter**: Limit scope based on a key or key/value pair\n-   **Tag filter**: Limit scope based on an in-text tag\n-   **List and clear filters**: List all current filters and clear one or all\n-   **List notes in scope**: List notes that will be processed.\n\n**Bulk Edit Metadata** from a CSV file (See the _[Make Bulk Updates](https://github.com/natelandau/obsidian-metadata#make-bulk-updates)_ section below)\n\n**Add Metadata**: Add new metadata to your vault.\n\nWhen adding a new key to inline metadata, the `insert location` value in the config file will specify where in the note it will be inserted.\n\n-   **Add new metadata to the frontmatter**\n-   **Add new inline metadata** - Set `insert_location` in the config to control where the new metadata is inserted. (Default: Bottom)\n-   **Add new inline tag** - Set `insert_location` in the config to control where the new tag is inserted. (Default: Bottom)\n\n**Rename Metadata**: Rename either a key and all associated values, a specific value within a key. or an in-text tag.\n\n-   **Rename a key**\n-   **Rename a value**\n-   **Rename an inline tag**\n\n**Delete Metadata**: Delete either a key and all associated values, or a specific value.\n\n-   **Delete a key and associated values**\n-   **Delete a value from a key**\n-   **Delete an inline tag**\n\n**Move Inline Metadata**: Move inline metadata to a specified location with a note\n\n-   **Move to Top**: Move all inline metadata beneath the frontmatter\n-   **Move to After Title**: Move all inline metadata beneath the first markdown header\n-   **Move to Bottom**: Move all inline metadata to the bottom of the note\n\n**Transpose Metadata**: Move metadata from inline to frontmatter or the reverse.\n\nWhen transposing to inline metadata, the `insert location` value in the config file will specify where in the note it will be inserted.\n\n-   **Transpose all metadata** - Moves all frontmatter to inline metadata, or the reverse\n-   **Transpose key** - Transposes a specific key and all it's values\n-   **Transpose value**- Transpose a specific key:value pair\n\n**Review Changes**: Prior to committing changes, review all changes that will be made.\n\n-   **View a diff of the changes** that will be made\n\n**Commit Changes**: Write the changes to disk. This step is not undoable.\n\n-   **Commit changes to the vault**\n\n### Known Limitations\n\nMulti-level frontmatter is not supported.\n\n```yaml\n# This works perfectly well\n---\nkey: \"value\"\nkey2:\n    - one\n    - two\n    - three\nkey3: [\"foo\", \"bar\", \"baz\"]\nkey4: value\n\n# This will not work\n---\nkey1:\n    key2:\n        - one\n        - two\n        - three\n    key3:\n        - one\n        - two\n        - three\n---\n```\n\n### Configuration\n\n`obsidian-metadata` requires a configuration file at `~/.obsidian_metadata.toml`. On first run, this file will be created. You can specify a new location for the configuration file with the `--config-file` option.\n\nTo add additional vaults, copy the default section and add the appropriate information. The script will prompt you to select a vault if multiple exist in the configuration file\n\nBelow is an example with two vaults.\n\n```toml\n[\"Vault One\"] # Name of the vault.\n\n    # Path to your obsidian vault\n    # Note for Windows users: Windows paths must use `\\\\` as the path separator due to a limitation with how TOML parses strings.\n    #       Example: \"C:\\\\Users\\\\username\\\\Documents\\\\Obsidian\"\n    path = \"/path/to/vault\"\n\n    # Folders within the vault to ignore when indexing metadata\n    exclude_paths = [\".git\", \".obsidian\"]\n\n    # Location to add metadata. One of:\n    #    TOP:            Directly after frontmatter.\n    #    AFTER_TITLE:    After the first header following frontmatter.\n    #    BOTTOM:         The bottom of the note\n    insert_location = \"BOTTOM\"\n\n[\"Vault Two\"]\n    path = \"/path/to/second_vault\"\n    exclude_paths = [\".git\", \".obsidian\", \"daily_notes\"]\n    insert_location = \"AFTER_TITLE\"\n```\n\nTo bypass the configuration file and specify a vault to use at runtime use the `--vault-path` option.\n\n**Note for Windows users:**\nDue to how TOMML parses strings, Windows paths must use `\\\\` as the path separator.\nFor example: `C:\\\\Users\\\\username\\\\Documents\\\\Obsidian`\n\n### Make Bulk Updates\n\nBulk edits are supported by importing a CSV file containing the following columns. Column headers must be lowercase.\n\n1. `path` - Path to note relative to the vault root folder\n2. `type` - Type of metadata. One of `frontmatter`, `inline_metadata`, or `tag`\n3. `key` - The key to add (leave blank for a tag)\n4. `value` - the value to add to the key\n\nAn example valid CSV file is\n\n```csv\npath,type,key,value\nfolder 1/note1.md,frontmatter,fruits,apple\nfolder 1/note1.md,frontmatter,fruits,banana\nfolder 1/note1.md,inline_metadata,cars,toyota\nfolder 1/note1.md,inline_metadata,cars,honda\nfolder 1/note1.md,tag,,tag1\nfolder 1/note1.md,tag,,tag2\n```\n\nHow bulk imports work:\n\n-   **Only notes which match the path in the CSV file are updated**\n-   **Effected notes will have ALL of their metadata changed** to reflect the values in the CSV file\n-   **Existing metadata in a matching note will be rewritten**. This may result in it's location and/or formatting within the note being changed\n-   Inline tags ignore any value added to the `key` column\n\nCreate a CSV template for making bulk updates containing all your notes and their associated metadata by\n\n1. Using the `--export-template` cli command; or\n2. Selecting the `Metadata by note` option within the `Export Metadata` section of the app\n\nOnce you have a template created you can import it using the `--import-csv` flag or by navigating to the `Import bulk changes from CSV` option.\n\n# Contributing\n\n## Setup: Once per project\n\nThere are two ways to contribute to this project.\n\n### 1. Containerized development\n\n1. Clone this repository. `git clone https://github.com/natelandau/obsidian-metadata`\n2. Open the repository in Visual Studio Code\n3. Start the [Dev Container](https://code.visualstudio.com/docs/remote/containers). Run \u003ckbd\u003eCtrl/⌘\u003c/kbd\u003e + \u003ckbd\u003e⇧\u003c/kbd\u003e + \u003ckbd\u003eP\u003c/kbd\u003e → _Remote-Containers: Reopen in Container_.\n4. Run `poetry env info -p` to find the PATH to the Python interpreter if needed by VSCode.\n\n### 2. Local development\n\n1. Install Python 3.10 and [Poetry](https://python-poetry.org)\n2. Clone this repository. `git clone https://github.com/natelandau/obsidian-metadata`\n3. Install the Poetry environment with `poetry install`.\n4. Activate your Poetry environment with `poetry shell`.\n5. Install the pre-commit hooks with `pre-commit install --install-hooks`.\n\n## Developing\n\n-   This project follows the [Conventional Commits](https://www.conventionalcommits.org/) standard to automate [Semantic Versioning](https://semver.org/) and [Keep A Changelog](https://keepachangelog.com/) with [Commitizen](https://github.com/commitizen-tools/commitizen).\n    -   When you're ready to commit changes run `cz c`\n-   Run `poe` from within the development environment to print a list of [Poe the Poet](https://github.com/nat-n/poethepoet) tasks available to run on this project. Common commands:\n    -   `poe lint` runs all linters\n    -   `poe test` runs all tests with Pytest\n-   Run `poetry add {package}` from within the development environment to install a run time dependency and add it to `pyproject.toml` and `poetry.lock`.\n-   Run `poetry remove {package}` from within the development environment to uninstall a run time dependency and remove it from `pyproject.toml` and `poetry.lock`.\n-   Run `poetry update` from within the development environment to upgrade all dependencies to the latest versions allowed by `pyproject.toml`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnatelandau%2Fobsidian-metadata","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnatelandau%2Fobsidian-metadata","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnatelandau%2Fobsidian-metadata/lists"}