Skip to main content

A golden conversation thread crossing several archives

⌇ ariadne

Find the conversation.
Turn scattered X/Twitter archives and tweet datasets into readable, attributable reply branches.

documentation · PyPI · Python API · MIT


A social export remembers posts. The conversation around them is often somewhere else: a parent in another archive, a quote in a community dataset, an older post in the cache.

Ariadne merges those sources, selects the posts you care about, follows every known reply-parent chain toward its root, attaches quote context, and renders the result root → target.

It does not pretend sparse data is complete. Missing posts stay visible as placeholders and warnings unless you ask for --strict.

Start here

Requires Python 3.11 or newer. The distribution is ariadne-x; the command and import are both ariadne.

uv tool install ariadne-x
ariadne interactive

Or build directly from a personal archive:

ariadne build \
  --archive ~/Downloads/twitter-archive.zip \
  --for-user alice \
  --since 2024-01-01 \
  --format markdown \
  --output conversations.md

That is the whole basic loop:

archives + dumps + cache
          ↓
     choose targets
          ↓
follow known parent IDs
          ↓
 quotes + root-to-target branches

Choose your path

You have… Use…
One X/Twitter export ariadne build --archive PATH …
CSV, JSON, JSONL, or NDJSON ariadne build --tweets-file PATH …
Tweet IDs or X URLs Pass them after ariadne build
Archives you will reuse ariadne dumps import PATH
A public X account ariadne build --target-user USER …
A Bluesky handle ariadne bluesky HANDLE …

Imported archives form a local, searchable library:

ariadne dumps import ~/Downloads/twitter-archive.zip --name personal
ariadne dumps search "remembered phrase" --user alice
ariadne dumps show https://x.com/alice/status/1234567890123456789

# Imported dumps join ordinary builds automatically.
ariadne build --for-user alice --since 2024-01-01 --format raft -o alice.jsonl

Each import becomes a self-contained SQLite database under ~/.ariadne/dumps. The source is never modified, and removing an import never removes the source. Parquet imports additionally need DuckDB:

uv tool install 'ariadne-x[parquet]'

Read the archive library guide →

From Python

The CLI is a thin front end over a typed synchronous API:

from pathlib import Path
import ariadne

options = ariadne.BuildOptions(
    archive=Path.home() / "Downloads" / "twitter-archive.zip",
    for_user="alice",
    since="2024-01-01",
)

result = ariadne.build(options)

for conversation in result:
    print(conversation.target_id)

documents = result.raft_documents()
result.save("out/branches.jsonl", "raft")

Use no_dumps=True when a build must ignore the persistent archive library. Named failures derive from AriadneError, including ConfigurationError, NoTargetsError, ReconstructionError, and SourceError.

Read the Python API reference →

Pick an output

Format Shape Good for
messages enriched JSON conversations chat-like data with tweet metadata; the CLI default
openai reduced JSON conversations nested role, name, and content messages
json normalized graph + tweets analysis, provenance, and custom rendering
markdown text humans, notebooks, and review
raft one JSON object per line retrieval, chunking, and embedding

The openai renderer keeps Ariadne's conversation envelope; consumers extract conversations[i].messages. Roles follow authorship: the collected user's tweets speak as assistant, everyone else's as user (participant in the raft format) — even when a conversation's own tweets can't tell, because the build knows who was collected. In markdown, consecutive tweets by the same person merge into one message: one role header, the metadata of every tweet in the run, then the texts separated by --- rules.

Pass --responses-only (API: responses_only=True) to keep only conversations in which the subject actually responds — replies to or quote-tweets someone else. Standalone tweets and pure self-threads are dropped; a reply to a deleted tweet counts as a response, since the missing parent was somebody. ariadne interactive asks the same question.

Inspect the schemas →

What Ariadne follows

  • One target's ancestor path back to its root—not sibling replies or a whole tree.
  • Older parents even when --since limits the starting targets.
  • Reply and quote edges across different imported dumps.
  • Quote context, with root quote-tweets spliced onto their quoted post by default.

Ordinary archive builds stay local. --target-user is the convenience exception: it tries unofficial RSS and oEmbed unless disabled. Those sources can recover recent text but usually cannot prove reply edges. X API reads are separately opt-in through --fetch and --fetch-user-timeline and may be billable.

Read the source and network policy →

A few useful commands

ariadne inspect-archive ~/Downloads/twitter-archive.zip
ariadne dumps interactive
ariadne build --help

# Bluesky uses its public API and the same renderers.
ariadne bluesky alice.bsky.social --since 2024-01-01 --format raft

Picking up where a build left off

Every build that fetches anything writes a cache (.ariadne-cache.json by default) — and since 0.6 it also records the tweet ids it could not resolve, so the holes survive the session:

ariadne cache list                 # what each cache holds, and what is still missing
ariadne cache missing              # the missing ids, one per line
ariadne cache retry                # fetch them now, updating the cache in place

cache retry (API: ariadne.retry_cache()) tries local dumps and free oEmbed by default; add --community-archive, --twitterapi-key, or --fetch with an X API token for the stubborn ones, and --limit to bound a run. Re-running the original ariadne build afterwards picks the recovered tweets up from the cache. The cache write is last-writer-wins, so retry after a build using the same cache has finished, not alongside it.

Reference

Development

uv sync --extra dev --extra parquet
uv run pytest
uv run ruff check .
uv run mypy src

MIT licensed. The thread was there all along.

Download files

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

Source Distribution

ariadne_x-0.6.0.tar.gz (100.3 kB view details)

Uploaded Source

Built Distribution

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

ariadne_x-0.6.0-py3-none-any.whl (73.6 kB view details)

Uploaded Python 3

File details

Details for the file ariadne_x-0.6.0.tar.gz.

File metadata

  • Download URL: ariadne_x-0.6.0.tar.gz
  • Upload date:
  • Size: 100.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for ariadne_x-0.6.0.tar.gz
Algorithm Hash digest
SHA256 d616bd52569fcbf3b953c0d38559611e7a095f36892ac8acc79abc2e32a01bd8
MD5 8bd880fa45fc35c67b7f46b5e11ba8db
BLAKE2b-256 bf11975b3460110c130424cc439fd917bed27ca887d7c841f3b9d67fc4c1c15c

See more details on using hashes here.

Provenance

The following attestation bundles were made for ariadne_x-0.6.0.tar.gz:

Publisher: publish.yml on lumpenspace/ariadne

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ariadne_x-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: ariadne_x-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 73.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for ariadne_x-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 396b40276043162da4ec1ea473463c62f7366a7eba4cd436ab98004276cdb81a
MD5 7e5a93923329973c377baaaf7272aa52
BLAKE2b-256 a0e70ebae4f96943e53728d7465c8d74c1f86f7de0dcbff2f1ac678c02cdf1ad

See more details on using hashes here.

Provenance

The following attestation bundles were made for ariadne_x-0.6.0-py3-none-any.whl:

Publisher: publish.yml on lumpenspace/ariadne

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.6.0 This release

2 files

0.5.1

2 files

0.5.0

2 files

Supported by

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