Skip to main content

Follow X accounts and archive new posts as local Markdown — for Obsidian, search, and downstream LLM workflows.

Project description

x-to-obsidian

Follow a set of X (Twitter) accounts and archive every new post as local Markdown — for Obsidian, search, and LLM workflows.

One file per post, fetched incrementally: a durable, searchable archive of the sources you care about. Obsidian-friendly, not Obsidian-only.

How it's different

Many "tweet to Markdown" tools focus on saving a single post or thread on demand, or doing a one-time import of an existing Twitter archive. x-to-obsidian is built for the opposite job: define a set of accounts once, and keep a local Markdown archive up to date over repeated runs. It tracks what it has already fetched, so each run only pulls what's new.

It's for staying current with a watchlist, not capturing one post.

Who it's for

  • Traders keeping a watchlist of accounts and catalysts searchable offline
  • Researchers and analysts following a field without living in the timeline
  • Journalists monitoring a set of sources over time
  • Anyone maintaining a niche-topic feed they want as a local, queryable corpus

The real job isn't "tweets in Obsidian" — it's "a local, queryable archive of the sources I follow," whatever you do with it next.

What it does

  • Pulls posts from the accounts you list and writes one Markdown note per post to <vault>/<handle>/YYYY-MM-DD-<post_id>.md.
  • Tracks per-account state in SQLite, so reruns only fetch what's new.
  • Optionally downloads post media alongside each note.
  • Writes a per-run manifest so you can see exactly what was added each run.

What it does not do

No analysis, no summaries, no LLM. It's a clean ETL into Markdown — what you build on top (search, an LLM over the folder, a dashboard) is up to you.

Requirements

  • Python 3.12 and uv
  • An X (Twitter) API bearer token with read access — create a project/app at the X developer portal. Access tiers and rate limits are set by X.
  • Linux, macOS, or WSL2. Native (non-WSL) Windows is not supported: a C:\... path is translated to /mnt/c/..., which only makes sense under WSL.

Install

pip install x-to-obsidian        # or: uv tool install x-to-obsidian

This gives you the x-to-obsidian command. You'll also need a .env and an accounts.yaml — copy the templates from this repo (.env.example, accounts.example.yaml) and edit them. For development, clone the repo and use uv sync + uv run x-to-obsidian as shown below.

Setup

uv sync                                  # install dependencies

cp .env.example .env                     # set X_BEARER_TOKEN and VAULT_PATH
cp accounts.example.yaml accounts.yaml   # list the handles you want to follow
  • .env holds your bearer token, the destination folder (VAULT_PATH — an Obsidian vault is the usual choice, but any folder works), and toggles (replies, retweets, media, subfolders).
  • accounts.yaml is one entry per handle. Set enabled: false to skip an account without removing it.

Usage

uv run x-to-obsidian init           # create the database and check your config
uv run x-to-obsidian fetch          # mock mode: reads a bundled sample, makes no API calls
uv run x-to-obsidian fetch --live   # fetch from the live X API
uv run x-to-obsidian status         # accounts, last-fetched times, total post count

Notes are written to <vault>/<handle>/YYYY-MM-DD-<post_id>.md.

Common options:

  • fetch --since-days N — only the last N days
  • fetch --account <handle> — a single account
  • fetch --no-media — skip media downloads
  • reemit — rebuild notes from the database without calling the API

Run uv run x-to-obsidian --help for the full list.

How it works

Each post is saved to a local SQLite database before the next API call, so a run can stop and resume safely — the next run continues where it left off and fetches only new posts. See ARCHITECTURE.md for the internals.

License

MIT — see LICENSE.

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

x_to_obsidian-0.1.2.tar.gz (60.1 kB view details)

Uploaded Source

Built Distribution

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

x_to_obsidian-0.1.2-py3-none-any.whl (30.7 kB view details)

Uploaded Python 3

File details

Details for the file x_to_obsidian-0.1.2.tar.gz.

File metadata

  • Download URL: x_to_obsidian-0.1.2.tar.gz
  • Upload date:
  • Size: 60.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for x_to_obsidian-0.1.2.tar.gz
Algorithm Hash digest
SHA256 d8c5839a2bf20f7012693ac0755d016f01733a0d967bd56b6f291b7dce2e0a2b
MD5 cc9617efd99ba075991117c1f5834cfe
BLAKE2b-256 9cfb8dbbccfa533ed2597a4270f466d593e307c0ed3d793db36241b2802a5a49

See more details on using hashes here.

File details

Details for the file x_to_obsidian-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: x_to_obsidian-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 30.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for x_to_obsidian-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 53b75b4116a27b077889edaaf855d1654f3dd9583bb75db63ea4df1619cd7917
MD5 15511bfab339c06bca5a23c86be54df9
BLAKE2b-256 252986d0b35f66b0875d845316e5b934924ab401c3ccbc2573d2891255158851

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