ariadne-x 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ariadne_x-0.5.0/.github/workflows/ci.yml +29 -0
- ariadne_x-0.5.0/.github/workflows/publish.yml +47 -0
- ariadne_x-0.5.0/.gitignore +13 -0
- ariadne_x-0.5.0/LICENSE +22 -0
- ariadne_x-0.5.0/PKG-INFO +216 -0
- ariadne_x-0.5.0/README.md +185 -0
- ariadne_x-0.5.0/RELEASING.md +24 -0
- ariadne_x-0.5.0/docs/API.md +216 -0
- ariadne_x-0.5.0/docs/DUMPS.md +144 -0
- ariadne_x-0.5.0/docs/HYPERPLEX.md +39 -0
- ariadne_x-0.5.0/docs/RAFT.md +34 -0
- ariadne_x-0.5.0/docs/SCHEMA.md +75 -0
- ariadne_x-0.5.0/docs/SOURCES.md +73 -0
- ariadne_x-0.5.0/examples/fixture_archive/data/account.js +10 -0
- ariadne_x-0.5.0/examples/fixture_archive/data/tweets.js +19 -0
- ariadne_x-0.5.0/examples/generic.jsonl +3 -0
- ariadne_x-0.5.0/pyproject.toml +68 -0
- ariadne_x-0.5.0/src/ariadne/__init__.py +89 -0
- ariadne_x-0.5.0/src/ariadne/__main__.py +6 -0
- ariadne_x-0.5.0/src/ariadne/_types.py +9 -0
- ariadne_x-0.5.0/src/ariadne/api.py +1001 -0
- ariadne_x-0.5.0/src/ariadne/archive.py +247 -0
- ariadne_x-0.5.0/src/ariadne/bluesky.py +196 -0
- ariadne_x-0.5.0/src/ariadne/cli.py +987 -0
- ariadne_x-0.5.0/src/ariadne/dumps.py +1182 -0
- ariadne_x-0.5.0/src/ariadne/errors.py +41 -0
- ariadne_x-0.5.0/src/ariadne/fetch.py +365 -0
- ariadne_x-0.5.0/src/ariadne/hx.py +169 -0
- ariadne_x-0.5.0/src/ariadne/ids.py +66 -0
- ariadne_x-0.5.0/src/ariadne/models.py +155 -0
- ariadne_x-0.5.0/src/ariadne/providers.py +284 -0
- ariadne_x-0.5.0/src/ariadne/py.typed +0 -0
- ariadne_x-0.5.0/src/ariadne/reconstruct.py +198 -0
- ariadne_x-0.5.0/src/ariadne/render.py +238 -0
- ariadne_x-0.5.0/src/ariadne/sources.py +254 -0
- ariadne_x-0.5.0/src/ariadne/store.py +126 -0
- ariadne_x-0.5.0/src/ariadne/timeutil.py +65 -0
- ariadne_x-0.5.0/src/ariadne/unofficial.py +204 -0
- ariadne_x-0.5.0/tests/conftest.py +14 -0
- ariadne_x-0.5.0/tests/test_api.py +269 -0
- ariadne_x-0.5.0/tests/test_ariadne.py +514 -0
- ariadne_x-0.5.0/tests/test_dumps.py +627 -0
- ariadne_x-0.5.0/tests/test_dumps_cli.py +242 -0
- ariadne_x-0.5.0/tests/test_sources.py +188 -0
- ariadne_x-0.5.0/uv.lock +210 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
fail-fast: false
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: ${{ matrix.python-version }}
|
|
21
|
+
|
|
22
|
+
- name: Install package with dev dependencies
|
|
23
|
+
run: python -m pip install -e ".[dev]"
|
|
24
|
+
|
|
25
|
+
- name: Lint
|
|
26
|
+
run: ruff check .
|
|
27
|
+
|
|
28
|
+
- name: Test
|
|
29
|
+
run: pytest
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
|
|
13
|
+
- uses: actions/setup-python@v5
|
|
14
|
+
with:
|
|
15
|
+
python-version: "3.x"
|
|
16
|
+
|
|
17
|
+
- name: Install package with dev dependencies
|
|
18
|
+
run: python -m pip install -e ".[dev]"
|
|
19
|
+
|
|
20
|
+
- name: Lint
|
|
21
|
+
run: ruff check .
|
|
22
|
+
|
|
23
|
+
- name: Test
|
|
24
|
+
run: pytest
|
|
25
|
+
|
|
26
|
+
publish:
|
|
27
|
+
needs: test
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
environment: pypi
|
|
30
|
+
permissions:
|
|
31
|
+
contents: read
|
|
32
|
+
id-token: write
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v4
|
|
35
|
+
|
|
36
|
+
- uses: actions/setup-python@v5
|
|
37
|
+
with:
|
|
38
|
+
python-version: "3.x"
|
|
39
|
+
|
|
40
|
+
- name: Install build tools
|
|
41
|
+
run: python -m pip install --upgrade build
|
|
42
|
+
|
|
43
|
+
- name: Build package
|
|
44
|
+
run: python -m build
|
|
45
|
+
|
|
46
|
+
- name: Publish to PyPI
|
|
47
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
ariadne_x-0.5.0/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Claudio Brandolino
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
ariadne_x-0.5.0/PKG-INFO
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: ariadne-x
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Reconstruct reply branches from X/Twitter archives or IDs and render them as LLM chat inputs.
|
|
5
|
+
Project-URL: Homepage, https://ariadne.hyperplex.org
|
|
6
|
+
Project-URL: Repository, https://github.com/lumpenspace/ariadne
|
|
7
|
+
Project-URL: Issues, https://github.com/lumpenspace/ariadne/issues
|
|
8
|
+
Author: Claudio Brandolino
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Text Processing
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: rich>=13.7
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
25
|
+
Requires-Dist: duckdb>=1.1; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
28
|
+
Provides-Extra: parquet
|
|
29
|
+
Requires-Dist: duckdb>=1.1; extra == 'parquet'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
<p align="center">
|
|
33
|
+
<img src="site/public/ariadne-thread-v2.png" alt="A golden conversation thread crossing several archives" width="100%">
|
|
34
|
+
</p>
|
|
35
|
+
|
|
36
|
+
<h1 align="center">⌇ ariadne</h1>
|
|
37
|
+
|
|
38
|
+
<p align="center">
|
|
39
|
+
<strong>Find the conversation.</strong><br>
|
|
40
|
+
Turn scattered X/Twitter archives and tweet datasets into readable, attributable reply branches.
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
<p align="center">
|
|
44
|
+
<a href="https://ariadne.hyperplex.org">documentation</a> ·
|
|
45
|
+
<a href="https://pypi.org/project/ariadne-x/">PyPI</a> ·
|
|
46
|
+
<a href="docs/API.md">Python API</a> ·
|
|
47
|
+
<a href="LICENSE">MIT</a>
|
|
48
|
+
</p>
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
A social export remembers posts. The conversation around them is often somewhere
|
|
53
|
+
else: a parent in another archive, a quote in a community dataset, an older post in
|
|
54
|
+
the cache.
|
|
55
|
+
|
|
56
|
+
Ariadne merges those sources, selects the posts you care about, follows every known
|
|
57
|
+
reply-parent chain toward its root, attaches quote context, and renders the result
|
|
58
|
+
root → target.
|
|
59
|
+
|
|
60
|
+
It does not pretend sparse data is complete. Missing posts stay visible as
|
|
61
|
+
placeholders and warnings unless you ask for `--strict`.
|
|
62
|
+
|
|
63
|
+
## Start here
|
|
64
|
+
|
|
65
|
+
Requires Python 3.11 or newer. The distribution is `ariadne-x`; the command and
|
|
66
|
+
import are both `ariadne`.
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
uv tool install ariadne-x
|
|
70
|
+
ariadne interactive
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Or build directly from a personal archive:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
ariadne build \
|
|
77
|
+
--archive ~/Downloads/twitter-archive.zip \
|
|
78
|
+
--for-user alice \
|
|
79
|
+
--since 2024-01-01 \
|
|
80
|
+
--format markdown \
|
|
81
|
+
--output conversations.md
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
That is the whole basic loop:
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
archives + dumps + cache
|
|
88
|
+
↓
|
|
89
|
+
choose targets
|
|
90
|
+
↓
|
|
91
|
+
follow known parent IDs
|
|
92
|
+
↓
|
|
93
|
+
quotes + root-to-target branches
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Choose your path
|
|
97
|
+
|
|
98
|
+
| You have… | Use… |
|
|
99
|
+
| --- | --- |
|
|
100
|
+
| One X/Twitter export | `ariadne build --archive PATH …` |
|
|
101
|
+
| CSV, JSON, JSONL, or NDJSON | `ariadne build --tweets-file PATH …` |
|
|
102
|
+
| Tweet IDs or X URLs | Pass them after `ariadne build` |
|
|
103
|
+
| Archives you will reuse | `ariadne dumps import PATH` |
|
|
104
|
+
| A public X account | `ariadne build --target-user USER …` |
|
|
105
|
+
| A Bluesky handle | `ariadne bluesky HANDLE …` |
|
|
106
|
+
|
|
107
|
+
Imported archives form a local, searchable library:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
ariadne dumps import ~/Downloads/twitter-archive.zip --name personal
|
|
111
|
+
ariadne dumps search "remembered phrase" --user alice
|
|
112
|
+
ariadne dumps show https://x.com/alice/status/1234567890123456789
|
|
113
|
+
|
|
114
|
+
# Imported dumps join ordinary builds automatically.
|
|
115
|
+
ariadne build --for-user alice --since 2024-01-01 --format raft -o alice.jsonl
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Each import becomes a self-contained SQLite database under `~/.ariadne/dumps`.
|
|
119
|
+
The source is never modified, and removing an import never removes the source.
|
|
120
|
+
Parquet imports additionally need DuckDB:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
uv tool install 'ariadne-x[parquet]'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
[Read the archive library guide →](docs/DUMPS.md)
|
|
127
|
+
|
|
128
|
+
## From Python
|
|
129
|
+
|
|
130
|
+
The CLI is a thin front end over a typed synchronous API:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from pathlib import Path
|
|
134
|
+
import ariadne
|
|
135
|
+
|
|
136
|
+
options = ariadne.BuildOptions(
|
|
137
|
+
archive=Path.home() / "Downloads" / "twitter-archive.zip",
|
|
138
|
+
for_user="alice",
|
|
139
|
+
since="2024-01-01",
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
result = ariadne.build(options)
|
|
143
|
+
|
|
144
|
+
for conversation in result:
|
|
145
|
+
print(conversation.target_id)
|
|
146
|
+
|
|
147
|
+
documents = result.raft_documents()
|
|
148
|
+
result.save("out/branches.jsonl", "raft")
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Use `no_dumps=True` when a build must ignore the persistent archive library.
|
|
152
|
+
Named failures derive from `AriadneError`, including `ConfigurationError`,
|
|
153
|
+
`NoTargetsError`, `ReconstructionError`, and `SourceError`.
|
|
154
|
+
|
|
155
|
+
[Read the Python API reference →](docs/API.md)
|
|
156
|
+
|
|
157
|
+
## Pick an output
|
|
158
|
+
|
|
159
|
+
| Format | Shape | Good for |
|
|
160
|
+
| --- | --- | --- |
|
|
161
|
+
| `messages` | enriched JSON conversations | chat-like data with tweet metadata; the CLI default |
|
|
162
|
+
| `openai` | reduced JSON conversations | nested `role`, `name`, and `content` messages |
|
|
163
|
+
| `json` | normalized graph + tweets | analysis, provenance, and custom rendering |
|
|
164
|
+
| `markdown` | text | humans, notebooks, and review |
|
|
165
|
+
| `raft` | one JSON object per line | retrieval, chunking, and embedding |
|
|
166
|
+
|
|
167
|
+
The `openai` renderer keeps Ariadne's conversation envelope; consumers extract
|
|
168
|
+
`conversations[i].messages`. Role names describe position in the branch, not the
|
|
169
|
+
speaker's intent.
|
|
170
|
+
|
|
171
|
+
[Inspect the schemas →](docs/SCHEMA.md)
|
|
172
|
+
|
|
173
|
+
## What Ariadne follows
|
|
174
|
+
|
|
175
|
+
- One target's ancestor path back to its root—not sibling replies or a whole tree.
|
|
176
|
+
- Older parents even when `--since` limits the starting targets.
|
|
177
|
+
- Reply and quote edges across different imported dumps.
|
|
178
|
+
- Quote context, with root quote-tweets spliced onto their quoted post by default.
|
|
179
|
+
|
|
180
|
+
Ordinary archive builds stay local. `--target-user` is the convenience exception: it
|
|
181
|
+
tries unofficial RSS and oEmbed unless disabled. Those sources can recover recent text
|
|
182
|
+
but usually cannot prove reply edges. X API reads are separately opt-in through
|
|
183
|
+
`--fetch` and `--fetch-user-timeline` and may be billable.
|
|
184
|
+
|
|
185
|
+
[Read the source and network policy →](docs/SOURCES.md)
|
|
186
|
+
|
|
187
|
+
## A few useful commands
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
ariadne inspect-archive ~/Downloads/twitter-archive.zip
|
|
191
|
+
ariadne dumps interactive
|
|
192
|
+
ariadne build --help
|
|
193
|
+
|
|
194
|
+
# Bluesky uses its public API and the same renderers.
|
|
195
|
+
ariadne bluesky alice.bsky.social --since 2024-01-01 --format raft
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Reference
|
|
199
|
+
|
|
200
|
+
- [Documentation site](https://ariadne.hyperplex.org)
|
|
201
|
+
- [Persistent archive library](docs/DUMPS.md)
|
|
202
|
+
- [Python API](docs/API.md)
|
|
203
|
+
- [Source behavior](docs/SOURCES.md)
|
|
204
|
+
- [Output schemas](docs/SCHEMA.md)
|
|
205
|
+
- [Raft handoff](docs/RAFT.md)
|
|
206
|
+
|
|
207
|
+
## Development
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
uv sync --extra dev --extra parquet
|
|
211
|
+
uv run pytest
|
|
212
|
+
uv run ruff check .
|
|
213
|
+
uv run mypy src
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
MIT licensed. The thread was there all along.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="site/public/ariadne-thread-v2.png" alt="A golden conversation thread crossing several archives" width="100%">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">⌇ ariadne</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Find the conversation.</strong><br>
|
|
9
|
+
Turn scattered X/Twitter archives and tweet datasets into readable, attributable reply branches.
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://ariadne.hyperplex.org">documentation</a> ·
|
|
14
|
+
<a href="https://pypi.org/project/ariadne-x/">PyPI</a> ·
|
|
15
|
+
<a href="docs/API.md">Python API</a> ·
|
|
16
|
+
<a href="LICENSE">MIT</a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
A social export remembers posts. The conversation around them is often somewhere
|
|
22
|
+
else: a parent in another archive, a quote in a community dataset, an older post in
|
|
23
|
+
the cache.
|
|
24
|
+
|
|
25
|
+
Ariadne merges those sources, selects the posts you care about, follows every known
|
|
26
|
+
reply-parent chain toward its root, attaches quote context, and renders the result
|
|
27
|
+
root → target.
|
|
28
|
+
|
|
29
|
+
It does not pretend sparse data is complete. Missing posts stay visible as
|
|
30
|
+
placeholders and warnings unless you ask for `--strict`.
|
|
31
|
+
|
|
32
|
+
## Start here
|
|
33
|
+
|
|
34
|
+
Requires Python 3.11 or newer. The distribution is `ariadne-x`; the command and
|
|
35
|
+
import are both `ariadne`.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
uv tool install ariadne-x
|
|
39
|
+
ariadne interactive
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Or build directly from a personal archive:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
ariadne build \
|
|
46
|
+
--archive ~/Downloads/twitter-archive.zip \
|
|
47
|
+
--for-user alice \
|
|
48
|
+
--since 2024-01-01 \
|
|
49
|
+
--format markdown \
|
|
50
|
+
--output conversations.md
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
That is the whole basic loop:
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
archives + dumps + cache
|
|
57
|
+
↓
|
|
58
|
+
choose targets
|
|
59
|
+
↓
|
|
60
|
+
follow known parent IDs
|
|
61
|
+
↓
|
|
62
|
+
quotes + root-to-target branches
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Choose your path
|
|
66
|
+
|
|
67
|
+
| You have… | Use… |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| One X/Twitter export | `ariadne build --archive PATH …` |
|
|
70
|
+
| CSV, JSON, JSONL, or NDJSON | `ariadne build --tweets-file PATH …` |
|
|
71
|
+
| Tweet IDs or X URLs | Pass them after `ariadne build` |
|
|
72
|
+
| Archives you will reuse | `ariadne dumps import PATH` |
|
|
73
|
+
| A public X account | `ariadne build --target-user USER …` |
|
|
74
|
+
| A Bluesky handle | `ariadne bluesky HANDLE …` |
|
|
75
|
+
|
|
76
|
+
Imported archives form a local, searchable library:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
ariadne dumps import ~/Downloads/twitter-archive.zip --name personal
|
|
80
|
+
ariadne dumps search "remembered phrase" --user alice
|
|
81
|
+
ariadne dumps show https://x.com/alice/status/1234567890123456789
|
|
82
|
+
|
|
83
|
+
# Imported dumps join ordinary builds automatically.
|
|
84
|
+
ariadne build --for-user alice --since 2024-01-01 --format raft -o alice.jsonl
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Each import becomes a self-contained SQLite database under `~/.ariadne/dumps`.
|
|
88
|
+
The source is never modified, and removing an import never removes the source.
|
|
89
|
+
Parquet imports additionally need DuckDB:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
uv tool install 'ariadne-x[parquet]'
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
[Read the archive library guide →](docs/DUMPS.md)
|
|
96
|
+
|
|
97
|
+
## From Python
|
|
98
|
+
|
|
99
|
+
The CLI is a thin front end over a typed synchronous API:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from pathlib import Path
|
|
103
|
+
import ariadne
|
|
104
|
+
|
|
105
|
+
options = ariadne.BuildOptions(
|
|
106
|
+
archive=Path.home() / "Downloads" / "twitter-archive.zip",
|
|
107
|
+
for_user="alice",
|
|
108
|
+
since="2024-01-01",
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
result = ariadne.build(options)
|
|
112
|
+
|
|
113
|
+
for conversation in result:
|
|
114
|
+
print(conversation.target_id)
|
|
115
|
+
|
|
116
|
+
documents = result.raft_documents()
|
|
117
|
+
result.save("out/branches.jsonl", "raft")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Use `no_dumps=True` when a build must ignore the persistent archive library.
|
|
121
|
+
Named failures derive from `AriadneError`, including `ConfigurationError`,
|
|
122
|
+
`NoTargetsError`, `ReconstructionError`, and `SourceError`.
|
|
123
|
+
|
|
124
|
+
[Read the Python API reference →](docs/API.md)
|
|
125
|
+
|
|
126
|
+
## Pick an output
|
|
127
|
+
|
|
128
|
+
| Format | Shape | Good for |
|
|
129
|
+
| --- | --- | --- |
|
|
130
|
+
| `messages` | enriched JSON conversations | chat-like data with tweet metadata; the CLI default |
|
|
131
|
+
| `openai` | reduced JSON conversations | nested `role`, `name`, and `content` messages |
|
|
132
|
+
| `json` | normalized graph + tweets | analysis, provenance, and custom rendering |
|
|
133
|
+
| `markdown` | text | humans, notebooks, and review |
|
|
134
|
+
| `raft` | one JSON object per line | retrieval, chunking, and embedding |
|
|
135
|
+
|
|
136
|
+
The `openai` renderer keeps Ariadne's conversation envelope; consumers extract
|
|
137
|
+
`conversations[i].messages`. Role names describe position in the branch, not the
|
|
138
|
+
speaker's intent.
|
|
139
|
+
|
|
140
|
+
[Inspect the schemas →](docs/SCHEMA.md)
|
|
141
|
+
|
|
142
|
+
## What Ariadne follows
|
|
143
|
+
|
|
144
|
+
- One target's ancestor path back to its root—not sibling replies or a whole tree.
|
|
145
|
+
- Older parents even when `--since` limits the starting targets.
|
|
146
|
+
- Reply and quote edges across different imported dumps.
|
|
147
|
+
- Quote context, with root quote-tweets spliced onto their quoted post by default.
|
|
148
|
+
|
|
149
|
+
Ordinary archive builds stay local. `--target-user` is the convenience exception: it
|
|
150
|
+
tries unofficial RSS and oEmbed unless disabled. Those sources can recover recent text
|
|
151
|
+
but usually cannot prove reply edges. X API reads are separately opt-in through
|
|
152
|
+
`--fetch` and `--fetch-user-timeline` and may be billable.
|
|
153
|
+
|
|
154
|
+
[Read the source and network policy →](docs/SOURCES.md)
|
|
155
|
+
|
|
156
|
+
## A few useful commands
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
ariadne inspect-archive ~/Downloads/twitter-archive.zip
|
|
160
|
+
ariadne dumps interactive
|
|
161
|
+
ariadne build --help
|
|
162
|
+
|
|
163
|
+
# Bluesky uses its public API and the same renderers.
|
|
164
|
+
ariadne bluesky alice.bsky.social --since 2024-01-01 --format raft
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Reference
|
|
168
|
+
|
|
169
|
+
- [Documentation site](https://ariadne.hyperplex.org)
|
|
170
|
+
- [Persistent archive library](docs/DUMPS.md)
|
|
171
|
+
- [Python API](docs/API.md)
|
|
172
|
+
- [Source behavior](docs/SOURCES.md)
|
|
173
|
+
- [Output schemas](docs/SCHEMA.md)
|
|
174
|
+
- [Raft handoff](docs/RAFT.md)
|
|
175
|
+
|
|
176
|
+
## Development
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
uv sync --extra dev --extra parquet
|
|
180
|
+
uv run pytest
|
|
181
|
+
uv run ruff check .
|
|
182
|
+
uv run mypy src
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
MIT licensed. The thread was there all along.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
The PyPI distribution is `ariadne-x`; the Python import package and CLI
|
|
4
|
+
command remain `ariadne`. The package version is sourced from `__version__` in
|
|
5
|
+
`src/ariadne/__init__.py`, which Hatch reads through `pyproject.toml`.
|
|
6
|
+
|
|
7
|
+
## GitHub Release → PyPI Trusted Publishing
|
|
8
|
+
|
|
9
|
+
The one-time pending trusted publisher on PyPI uses:
|
|
10
|
+
|
|
11
|
+
- Project: `ariadne-x`
|
|
12
|
+
- Owner/repository: `lumpenspace/ariadne`
|
|
13
|
+
- Workflow: `publish.yml`
|
|
14
|
+
- Environment: `pypi`
|
|
15
|
+
|
|
16
|
+
For each release:
|
|
17
|
+
|
|
18
|
+
1. Bump `__version__` in `src/ariadne/__init__.py` and run `uv lock`.
|
|
19
|
+
2. Merge the release commit to `main` and wait for CI.
|
|
20
|
+
3. Publish a GitHub Release with a matching `vX.Y.Z` tag.
|
|
21
|
+
|
|
22
|
+
`.github/workflows/publish.yml` runs lint and tests, builds the sdist and wheel,
|
|
23
|
+
then uploads them to PyPI through OIDC. No PyPI password or API token is stored
|
|
24
|
+
in GitHub.
|