Skip to content

boxpositron/markdown-vault

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

65 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

markdown-vault

A production-ready REST API server for markdown vault management with comprehensive search, automation, and optional Obsidian compatibility. Built for CI/CD pipelines, cloud deployments, and programmatic markdown workflows.

PyPI version Python 3.10+ License: MIT Docker

Overview

markdown-vault is a standalone HTTP service providing a secure REST API for managing markdown files and vaults. Perfect for automation tools, CI/CD pipelines, or programmatic note access.

What it is: Independent REST API server for markdown vault operations
What it's not: Not an Obsidian plugin - runs as a standalone service with optional Obsidian vault support

Key Features

  • Full CRUD Operations - Create, read, update, delete markdown files via REST API
  • Advanced PATCH - Targeted updates with heading/block/frontmatter selectors
  • Periodic Notes - Daily, weekly, monthly, quarterly, yearly note support
  • Powerful Search - Text search and JSONLogic-based complex queries
  • Secure by Default - HTTPS with API key authentication
  • Production Ready - Docker support, 24/7 availability, cloud-native
  • Obsidian Compatible - API-compatible with Obsidian Local REST API plugin

Quick Start

Installation

Using uvx (Recommended - No Installation Required)

uvx markdown-vault start --reload

Using pip

pip install markdown-vault
markdown-vault start --reload

Using uv (Development)

git clone https://github.com/boxpositron/markdown-vault.git
cd markdown-vault
uv venv && uv sync
uv run markdown-vault start --reload

Using Docker (from GitHub Container Registry)

docker run -d \
  -p 27123:27123 \
  -v /path/to/vault:/vault \
  -e MARKDOWN_VAULT_VAULT__PATH=/vault \
  -e MARKDOWN_VAULT_SECURITY__API_KEY=your-key \
  ghcr.io/boxpositron/markdown-vault:latest

Configuration

Method 1: Config File

Create config.yaml:

server:
  host: "127.0.0.1"
  port: 27123
  https: true

vault:
  path: "/path/to/your/vault"
  auto_create: true

security:
  api_key: "your-secure-api-key-here"
  auto_generate_cert: true

Method 2: Environment Variables

export MARKDOWN_VAULT_SERVER__PORT=27123
export MARKDOWN_VAULT_VAULT__PATH=/path/to/vault
export MARKDOWN_VAULT_SECURITY__API_KEY=your-key
markdown-vault start

Method 3: CLI Flags

markdown-vault start --config config.yaml --reload

First Run

# Generate an API key
markdown-vault generate-key

# Start with auto-generated cert
markdown-vault start --reload

# Access API docs
open https://localhost:27123/docs

API Documentation

Visit https://localhost:27123/docs for interactive Swagger documentation.

Core Endpoints

# Vault Operations
GET    /vault/{filepath}        # Read file
PUT    /vault/{filepath}        # Create/update
POST   /vault/{filepath}        # Append
PATCH  /vault/{filepath}        # Targeted update
DELETE /vault/{filepath}        # Delete
GET    /vault/                  # List files

# Periodic Notes
GET    /periodic/daily/         # Get today's note
GET    /periodic/weekly/        # Get this week's note
GET    /periodic/monthly/       # Get this month's note
PUT    /periodic/daily/         # Update today's note
POST   /periodic/daily/         # Append to today's note

# Search
POST   /search/simple/          # Text search
POST   /search/                 # JSONLogic search

# System
GET    /                        # Server status
GET    /_/server/status         # Detailed status

Authentication

All requests require an API key:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://localhost:27123/vault/note.md

Advanced Features

PATCH Operations

Heading Targeting

# Append under specific heading
curl -X PATCH https://localhost:27123/vault/note.md \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Operation: append" \
  -H "Target-Type: heading" \
  -H "Target: Main Heading::Sub Heading:1" \
  -d "New content"

Block Reference

# Update at block reference
curl -X PATCH https://localhost:27123/vault/note.md \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Operation: replace" \
  -H "Target-Type: block" \
  -H "Target: ^abc123" \
  -d "Updated content"

Frontmatter

# Update YAML frontmatter
curl -X PATCH https://localhost:27123/vault/note.md \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Operation: replace" \
  -H "Target-Type: frontmatter" \
  -H "Target: tags" \
  -H "Content-Type: application/json" \
  -d '["new", "tags"]'

Search Examples

Simple Text Search

curl -X POST https://localhost:27123/search/simple/ \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "search term"}'

Complex JSONLogic Search

curl -X POST https://localhost:27123/search/ \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": {
      "and": [
        {"in": ["tag1", {"var": "frontmatter.tags"}]},
        {">=": [{"var": "frontmatter.priority"}, 5]}
      ]
    }
  }'

Development

Prerequisites

  • Python 3.10+
  • uv (recommended) or pip

Setup

# Clone repository
git clone https://github.com/boxpositron/markdown-vault.git
cd markdown-vault

# Install with uv (recommended)
uv venv
uv sync
source .venv/bin/activate  # or `.venv\Scripts\activate` on Windows

# Or install with pip
pip install -e ".[dev]"

Development Commands

# Run tests
make local-test                    # or: uv run pytest
make local-test-cov               # with coverage

# Code quality
make local-lint                    # ruff linting
make local-format                  # black formatting
make local-typecheck              # mypy type checking
make local-typecheck-pyright      # pyright type checking

# Run all QA checks
make local-qa                      # lint + format + typecheck + test

# Run server
make local-run                     # or: uv run markdown-vault start --reload

Project Structure

markdown-vault/
├── src/markdown_vault/
│   ├── api/              # FastAPI routes and dependencies
│   ├── core/             # Business logic (vault, search, patch)
│   ├── models/           # Pydantic models
│   └── utils/            # Utilities (crypto, dates)
├── tests/                # 351 tests, 86% coverage
├── docs/                 # Additional documentation
├── config/               # Example configurations
└── examples/             # Usage examples

Configuration Reference

Server Configuration

server:
  host: "127.0.0.1"          # Bind address
  port: 27123                 # Port number
  https: true                 # Enable HTTPS
  reload: false               # Auto-reload on changes (dev only)

Vault Configuration

vault:
  path: "/path/to/vault"      # Vault directory (required)
  auto_create: true            # Create directory if missing
  watch_files: false           # Watch for file changes
  respect_gitignore: true      # Honor .gitignore files

Security Configuration

security:
  api_key: "your-key"          # API authentication key
  cert_path: "./certs/server.crt"
  key_path: "./certs/server.key"
  auto_generate_cert: true     # Generate self-signed cert

Periodic Notes

periodic_notes:
  daily:
    enabled: true
    format: "YYYY-MM-DD"
    folder: "daily"
    template: "templates/daily.md"
  weekly:
    enabled: true
    format: "YYYY-[W]WW"
    folder: "weekly"
  monthly:
    enabled: true
    format: "YYYY-MM"
    folder: "monthly"

Logging

logging:
  level: "INFO"                # DEBUG, INFO, WARNING, ERROR
  format: "json"               # json or text
  file: null                   # Log file path (optional)

Deployment

Docker Compose

version: '3.8'
services:
  markdown-vault:
    image: ghcr.io/boxpositron/markdown-vault:latest
    ports:
      - "27123:27123"
    volumes:
      - ./vault:/vault
      - ./config.yaml:/app/config.yaml
    environment:
      - MARKDOWN_VAULT_VAULT__PATH=/vault
      - MARKDOWN_VAULT_SECURITY__API_KEY=${API_KEY}
    restart: unless-stopped

Systemd Service

[Unit]
Description=Markdown Vault REST API
After=network.target

[Service]
Type=simple
User=markdown
WorkingDirectory=/opt/markdown-vault
Environment="MARKDOWN_VAULT_VAULT__PATH=/data/vault"
Environment="MARKDOWN_VAULT_SECURITY__API_KEY=your-key"
ExecStart=/opt/markdown-vault/.venv/bin/markdown-vault start
Restart=always

[Install]
WantedBy=multi-user.target

Environment Variables

All configuration can be set via environment variables with the prefix MARKDOWN_VAULT_:

MARKDOWN_VAULT_SERVER__HOST=0.0.0.0
MARKDOWN_VAULT_SERVER__PORT=8080
MARKDOWN_VAULT_SERVER__HTTPS=false
MARKDOWN_VAULT_VAULT__PATH=/data/vault
MARKDOWN_VAULT_SECURITY__API_KEY=your-secure-key
MARKDOWN_VAULT_LOGGING__LEVEL=DEBUG

Obsidian Compatibility

markdown-vault is fully compatible with the Obsidian Local REST API plugin, allowing you to:

  • Access Obsidian vaults via API without the desktop app running
  • Use existing Obsidian-aware tools and integrations
  • Deploy Obsidian vault access to servers
  • Access multiple Obsidian vaults simultaneously

Configuration for Obsidian

vault:
  path: "/Users/you/Documents/MyObsidianVault"

obsidian:
  enabled: true               # Respect .obsidian/ directory
  config_sync: true           # Read Obsidian's periodic notes config

API Endpoints

Uses the same default port (27123) and endpoints as the Obsidian plugin:

  • Compatible with all Obsidian Local REST API clients
  • Drop-in replacement for automation scripts
  • Works whether Obsidian is running or not

Use Cases

  • CI/CD Integration - Auto-update documentation in build pipelines
  • Cloud Automation - Run as microservice for markdown workflows
  • Content Management - Headless CMS for markdown content
  • Knowledge Base API - REST API for documentation systems
  • Script Integration - Programmatic notes from any language
  • Obsidian Automation - API access without desktop dependency
  • Multi-Vault Management - Access multiple vaults concurrently

Testing

# Run all tests
make local-test

# With coverage
make local-test-cov

# Single test file
uv run pytest tests/test_vault.py -v

# Single test
uv run pytest tests/test_vault.py::test_create_file -v

# Watch mode (requires pytest-watch)
pytest-watch

Test Stats: 351 tests, 86% coverage

Troubleshooting

SSL Certificate Issues

# Generate new self-signed certificate
markdown-vault start --generate-cert

# Use HTTP instead (development only)
markdown-vault start --no-https

Permission Errors

# Ensure vault directory is writable
chmod -R u+w /path/to/vault

# Or set auto_create in config
vault:
  auto_create: true

Port Already in Use

# Use different port
markdown-vault start --port 8080

# Or set in config
server:
  port: 8080

Contributing

Contributions welcome! See CONTRIBUTING.md for guidelines.

Quick Contribution Guide

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes with tests
  4. Run QA checks (make local-qa)
  5. Commit (git commit -m 'Add amazing feature')
  6. Push (git push origin feature/amazing-feature)
  7. Open a Pull Request

Publishing & Releases

This project uses automated publishing with OIDC Trusted Publishing for security and convenience.

For Maintainers: Setting Up PyPI Trusted Publishing

One-time setup (requires PyPI account with project ownership):

  1. Go to PyPI Project Settings

  2. Add GitHub as Trusted Publisher

    • PyPI Project Name: markdown-vault
    • Owner: boxpositron
    • Repository name: markdown-vault
    • Workflow name: pypi-publish.yml
    • Environment name: pypi (optional but recommended)

Creating a Release

Releases are fully automated via GitHub Actions:

# 1. Update version in pyproject.toml
# 2. Update CHANGELOG.md
# 3. Commit changes
git add pyproject.toml CHANGELOG.md
git commit -m "chore: bump version to 0.0.2"

# 4. Create and push tag
git tag v0.0.2
git push origin main --tags

# 5. Create GitHub Release (triggers publishing)
gh release create v0.0.2 \
  --title "v0.0.2" \
  --notes "See CHANGELOG.md for details" \
  dist/*.whl dist/*.tar.gz

This automatically:

  • ✅ Builds Docker images (multi-platform: amd64/arm64)
  • ✅ Pushes to ghcr.io/boxpositron/markdown-vault
  • ✅ Publishes to PyPI
  • ✅ Generates SBOM and provenance attestations

Manual Publishing (Alternative)

If you need to publish manually:

# Build the package
uv build

# Publish using trusted publishing (no token needed!)
uv publish

Note: Manual publishing from GitHub Actions uses OIDC automatically. Local publishing requires a PyPI API token.

Verification

After publishing, verify the release:

# Test PyPI installation
pip install markdown-vault==0.0.2

# Test Docker image
docker pull ghcr.io/boxpositron/markdown-vault:0.0.2

# Verify attestations
docker buildx imagetools inspect ghcr.io/boxpositron/markdown-vault:0.0.2

Changelog

See CHANGELOG.md for version history.

License

MIT License - See LICENSE for details.

Author

David Ibia - pypi@boxpositron.dev

Credits

API compatibility with Obsidian Local REST API plugin by @coddingtonbear.

Obsidian is a trademark of Dynalist Inc. This project is independent and not affiliated with Obsidian or Dynalist Inc.

Links

About

A production-ready REST API server for markdown vault management with comprehensive search, automation, and optional Obsidian compatibility

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors