⌇ 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.
What Ariadne follows
- One target's ancestor path back to its root—not sibling replies or a whole tree.
- Older parents even when
--sincelimits 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
- Documentation site
- Persistent archive library
- Python API
- Source behavior
- Output schemas
- Raft handoff
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.
Metadata
Release files for ariadne-x 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| ariadne_x-0.6.0.tar.gz | 100.3 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ariadne_x-0.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 173.9 kB
Release files / ariadne_x-0.6.0.tar.gz
| Download URL | ariadne_x-0.6.0.tar.gz |
|---|---|
| Size | 100.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d616bd52569fcbf3b953c0d38559611e7a095f36892ac8acc79abc2e32a01bd8
|
|
BLAKE2b-256 checksum How to use checksums |
bf11975b3460110c130424cc439fd917bed27ca887d7c841f3b9d67fc4c1c15c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 21, 2026.
Transparency logRelease files / ariadne_x-0.6.0-py3-none-any.whl
| Download URL | ariadne_x-0.6.0-py3-none-any.whl |
|---|---|
| Size | 73.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
396b40276043162da4ec1ea473463c62f7366a7eba4cd436ab98004276cdb81a
|
|
BLAKE2b-256 checksum How to use checksums |
a0e70ebae4f96943e53728d7465c8d74c1f86f7de0dcbff2f1ac678c02cdf1ad
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 21, 2026.
Transparency logSecurity for ariadne-x 0.6.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for ariadne_x-0.6.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 21, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.