Skip to main content

Convert almost anything to Obsidian-flavored Markdown for a knowledge graph.

Project description

Any2MD

CI License: MIT Python 3.11+

Free, open-source CLI that converts almost anything — local files (PDF, DOCX, XLSX, images…) and online links (YouTube, Reddit, GitHub, arXiv, Wikipedia, Hacker News, Stack Overflow, Twitter/X, web articles) — into Obsidian-flavored Markdown for a knowledge graph. Every input is summarized. No external APIs, no API keys, ever.

Install

One command, anywhere (recommended — isolated, no venv to manage):

pipx install any2md-cli

Then just run it:

any2md

The first run asks one thing — where to save your .md files — and then gets out of the way. Summaries run locally: if Ollama is running it's used automatically, otherwise a built-in zero-setup extractive summarizer is used. Nothing else to configure.

From source (dev)
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

Usage

One-shot

any2md convert https://github.com/karpathy/nanoGPT
any2md convert ~/notes/paper.pdf -o ~/ObsidianVault/inbox
any2md convert https://arxiv.org/abs/1706.03762 --depth high --provider extractive
any2md convert --batch links.txt          # one target per line

Re-converting the same link refreshes the existing note instead of making a duplicate (tracking params like utm_* are stripped, so the same article always maps to one note). Pages that extract to nothing — paywalled or JavaScript-only — are skipped with a warning rather than written as empty notes.

Interactive REPL

any2md            # opens the REPL

Inside the REPL, paste a URL or file path to convert it. Commands:

Command Effect
/output <dir> set output folder
/provider <name> set summarizer: extractive (default) · ollama · none
/depth how much to keep: low · medium · high · raw (◀ ▶ live picker)
/batch <file> submit every line in a file
/jobs list jobs + status
/last path of the last written .md
/open [last] open the output folder (or the last note) in your file viewer
/rename <name> rename the file you just made (slug auto-cleaned)
/help · /quit help / exit

While a conversion runs you get a live spinner with an estimated time (it learns your real timings per source) and a rotating tip. Drag a file straight into the terminal to convert it.

Config

any2md config set output ~/ObsidianVault/inbox
any2md config set provider extractive
any2md config show

Precedence: CLI flag > env var (ANY2MD_OUTPUT_DIR, ANY2MD_PROVIDER, …) > ~/.any2md/config.toml > default.

Summarizers (all free, offline)

  • extractive (default): pure-Python TextRank-style. Zero setup, no network.
  • ollama: local model via OLLAMA_URL (default http://localhost:11434), OLLAMA_MODEL (default llama3.2). Unreachable → falls back to extraction-only.
  • none: extraction only, no summary.

Serve mode (HTTP)

any2md serve --port 8000

Routes:

# submit a conversion → returns {"id": "..."}
curl -X POST localhost:8000/convert -H 'Content-Type: application/json' \
     -d '{"target":"https://github.com/karpathy/nanoGPT"}'

curl localhost:8000/jobs/<id>            # status + progress
curl localhost:8000/jobs/<id>/download   # the rendered .md

Set ANY2MD_TOKEN to gate access — clients then send Authorization: Bearer <token>.

Deploy

Docker

docker build -t any2md .
docker run -p 8000:8000 -e ANY2MD_TOKEN=secret -v "$PWD/data:/data" any2md

Railway

Push the repo; Railway builds the Dockerfile and runs any2md serve on $PORT (see railway.toml). Set ANY2MD_TOKEN and ANY2MD_PROVIDER=extractive in the dashboard. No API keys required — the stack is fully free/offline.

Develop

pytest -q          # tests (no live network)
ruff check .       # lint

See CONTRIBUTING.md for the full workflow (TDD, fixtures, adding a source). CI runs the suite + lint on every push and PR.

Publish to PyPI (maintainer)

pipx install any2md-cli works once the package is on PyPI. To cut a release:

python -m build                 # builds dist/*.whl and dist/*.tar.gz
twine upload dist/*             # needs your PyPI account / API token

Bump __version__ in any2md/__init__.py first (pyproject.toml reads it dynamically).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

any2md_cli-0.1.3.tar.gz (72.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

any2md_cli-0.1.3-py3-none-any.whl (56.1 kB view details)

Uploaded Python 3

File details

Details for the file any2md_cli-0.1.3.tar.gz.

File metadata

  • Download URL: any2md_cli-0.1.3.tar.gz
  • Upload date:
  • Size: 72.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for any2md_cli-0.1.3.tar.gz
Algorithm Hash digest
SHA256 e2d32575eae1aba6f989aebdecc3b35ef228920de443c5c87b85b3f4859f41e2
MD5 1ed52a253d882fd237e859bbd41632e2
BLAKE2b-256 fb45adf6e7b82063b00d4ada4e99119f5aeabbe628718ca7f82215d5949b6ebb

See more details on using hashes here.

File details

Details for the file any2md_cli-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: any2md_cli-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 56.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for any2md_cli-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 9856354cf788b7bac2dbd83dd85ea62223bad0047c73f5cf66488ffe3656442b
MD5 e4ccdc3f8dfc16027bcee1fcdb05c184
BLAKE2b-256 ff1255af481f68eea5785d11b5144fd6af54c7400e9fe7da7874f066e57bb6a7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page