unisessions 0.1.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 vibheksoni
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.
@@ -0,0 +1,617 @@
1
+ Metadata-Version: 2.4
2
+ Name: unisessions
3
+ Version: 0.1.0
4
+ Summary: Convert AI coding CLI sessions between Codex, Claude Code, Pi, OpenCode, Devin, and Factory. SDK, CLI, and MCP chat recall.
5
+ Author: vibheksoni
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/vibheksoni/session-export
8
+ Project-URL: Repository, https://github.com/vibheksoni/session-export
9
+ Project-URL: Issues, https://github.com/vibheksoni/session-export/issues
10
+ Keywords: ai-cli,ai-coding,coding-agent,cli-tool,developer-tools,session-converter,session-export,session-migration,session-search,chat-history,agent-memory,mcp-server,model-context-protocol,codex-cli,claude-code,opencode,pi-coding-agent
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Software Development :: Code Generators
18
+ Classifier: Topic :: Utilities
19
+ Requires-Python: >=3.11
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: tiktoken>=0.7.0
23
+ Provides-Extra: mcp
24
+ Requires-Dist: fastmcp>=2.0.0; extra == "mcp"
25
+ Provides-Extra: fast
26
+ Requires-Dist: orjson>=3.10.0; extra == "fast"
27
+ Requires-Dist: google-re2>=1.1; extra == "fast"
28
+ Dynamic: license-file
29
+
30
+ # UniSessions
31
+
32
+ UniSessions is an SDK-first AI CLI session converter for moving sessions between Codex, Claude Code, Pi, OpenCode, Devin, and Factory, with trace export for HuggingFace and fine-tuning, plus an MCP chat recall server built on top.
33
+
34
+ <div align="center">
35
+
36
+ ```
37
+
38
+ ▄▄▄ ▄▄ ▄▄▄▄▄
39
+ █▀██ ██ ██▀▀▀▀█▄
40
+ ██ ██ ▄ ▀▀ ▀██▄ ▄▀ ▀▀ ▄
41
+ ██ ██ ████▄ ██ ▀██▄▄ ▄█▀█▄ ▄██▀█ ▄██▀█ ██ ▄███▄ ████▄ ▄██▀█
42
+ ██ ██ ██ ██ ██ ▄ ▀██▄ ██▄█▀ ▀███▄ ▀███▄ ██ ██ ██ ██ ██ ▀███▄
43
+ ▀█████▄▄██ ▀█▄██ ▀██████▀▄▀█▄▄▄█▄▄██▀█▄▄██▀▄██▄▀███▀▄██ ▀██▄▄██▀
44
+
45
+ ```
46
+
47
+ **Convert one AI CLI session format into another across Codex, Pi, OpenCode, Claude Code, Devin, and Factory.**
48
+
49
+ I use a lot of AI coding CLIs Codex Claude Code Pi OpenCode Devin Factory and wanted to move a session from one tool into another without losing the useful conversation history
50
+
51
+ [![Python 3.11+](https://img.shields.io/badge/Python-3.11+-blue?logo=python&logoColor=white)](https://www.python.org/)
52
+ [![Tests](https://img.shields.io/badge/Tests-29%20passing-green)]()
53
+ [![Providers](https://img.shields.io/badge/Providers-6%20(Codex%20%7C%20Pi%20%7C%20OpenCode%20%7C%20Claude%20%7C%20Devin%20%7C%20Factory)-purple)]()
54
+ [![Conversions](https://img.shields.io/badge/Conversions-30%20directions-orange)]()
55
+ [![Traces](https://img.shields.io/badge/Trace%20Export-3%20formats-blue)]()
56
+ [![MCP](https://img.shields.io/badge/MCP-FastMCP-teal?logo=fastapi&logoColor=white)]()
57
+ [![License](https://img.shields.io/badge/License-MIT-yellow)]()
58
+ [![GitHub stars](https://img.shields.io/github/stars/vibheksoni/session-export?style=social)](https://github.com/vibheksoni/session-export/stargazers)
59
+
60
+ </div>
61
+
62
+ ---
63
+
64
+ ## Table of Contents
65
+
66
+ - [Why I built this](#why-i-built-this)
67
+ - [Quick Start](#quick-start)
68
+ - [Supported AI coding agents](#supported-ai-coding-agents)
69
+ - [All 30 conversion directions](#all-30-conversion-directions)
70
+ - [How to list sessions](#how-to-list-sessions)
71
+ - [How to convert sessions](#how-to-convert-sessions)
72
+ - [How to export traces](#how-to-export-traces)
73
+ - [How to handle conflicts](#how-to-handle-conflicts)
74
+ - [How to bulk export](#how-to-bulk-export)
75
+ - [How to use custom paths](#how-to-use-custom-paths)
76
+ - [MCP server for agent chat recall](#mcp-server-for-agent-chat-recall)
77
+ - [SDK usage](#sdk-usage)
78
+ - [Architecture](#architecture)
79
+ - [Default session paths](#default-session-paths)
80
+ - [Data fidelity](#data-fidelity)
81
+ - [Performance](#performance)
82
+ - [FAQ](#faq)
83
+ - [Contributing](#contributing)
84
+ - [Development](#development)
85
+ - [License](#license)
86
+
87
+ ## Why I built this
88
+
89
+ I looked for a tool that could convert one AI CLI session into another AI CLI session format and found nothing so I built one
90
+
91
+ I also wanted my agent to remember things from my other sessions like if I solved a bug in one project I wanted to tell it hey in that other session I fixed this by doing X and it would go check and learn from it instead of me explaining the same thing again
92
+
93
+ So this does two things
94
+
95
+ - Moves your sessions between Codex Pi OpenCode Claude Code Devin and Factory in any direction all 30 combinations
96
+ - Exports sessions as traces in HuggingFace STS OpenAI fine-tuning or ShareGPT format for Hub upload or model training
97
+ - Lets your agent search through all your old chat history across all projects and providers so it can recall what you did before and learn from it
98
+
99
+ Then I wanted the project to not be locked into a CLI or MCP its an SDK first so you can use it for other projects to do cool stuff like build a GUI for it or whatever you want the CLI and MCP server are just built on top of the SDK
100
+
101
+ ## Quick Start
102
+
103
+ Clone the repo and run from it directly
104
+
105
+ ```powershell
106
+ git clone https://github.com/vibheksoni/session-export.git
107
+ cd session-export
108
+ python -m unisessions list codex
109
+ python -m unisessions list pi
110
+ python -m unisessions list opencode
111
+ python -m unisessions list claude
112
+ python -m unisessions list devin
113
+ python -m unisessions list factory
114
+ ```
115
+
116
+ Convert a single session (dry-run first, then write):
117
+
118
+ ```powershell
119
+ python -m unisessions codex-to-pi <session-id>
120
+ python -m unisessions codex-to-pi <session-id> --write
121
+ python -m unisessions claude-to-pi <session-id> --write
122
+ python -m unisessions devin-to-pi <session-id> --write
123
+ python -m unisessions factory-to-pi <session-id> --write
124
+ ```
125
+
126
+ Export a session as a HuggingFace trace:
127
+
128
+ ```powershell
129
+ python -m unisessions to-trace codex <session-id> --format sts --write -o trace.jsonl
130
+ ```
131
+
132
+ Bulk export all Codex sessions to Pi:
133
+
134
+ ```powershell
135
+ python -m unisessions codex-to-pi-all --write --workers 8
136
+ ```
137
+
138
+ Search across all sessions via MCP:
139
+
140
+ ```powershell
141
+ python -m unisessions.mcp_server
142
+ ```
143
+
144
+ ## Supported AI coding agents
145
+
146
+ | Agent | Store | Session Format | Session IDs |
147
+ |---|---|---|---|
148
+ | [OpenAI Codex](https://github.com/openai/codex) | `codex` | JSONL rollout files under date tree | UUID v7 |
149
+ | [Pi](https://github.com/earendil-works/pi-coding-agent) | `pi` | JSONL append-only tree entries in cwd-encoded dirs | UUID v7 |
150
+ | [OpenCode](https://github.com/sst/opencode) | `opencode` | Official export/import JSON | `ses_` prefixed |
151
+ | [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | `claude` | JSONL transcript files in cwd-sanitized dirs | UUID v4 |
152
+ | [Devin](https://windsurf.com/devin) (Windsurf CLI) | `devin` | ATIF transcript JSON + SQLite metadata | slug names |
153
+ | [Factory](https://factory.ai) (Droid) | `factory` | JSONL transcript files with session headers | UUID v4 |
154
+
155
+ ## All 30 conversion directions
156
+
157
+ | From \ To | Pi | Codex | OpenCode | Claude | Devin | Factory |
158
+ |---|---|---|---|---|---|---|
159
+ | **Codex** | `codex-to-pi` | -- | `codex-to-opencode` | `codex-to-claude` | `codex-to-devin` | `codex-to-factory` |
160
+ | **Pi** | -- | `pi-to-codex` | `pi-to-opencode` | `pi-to-claude` | `pi-to-devin` | `pi-to-factory` |
161
+ | **OpenCode** | `opencode-to-pi` | `opencode-to-codex` | -- | `opencode-to-claude` | `opencode-to-devin` | `opencode-to-factory` |
162
+ | **Claude** | `claude-to-pi` | `claude-to-codex` | `claude-to-opencode` | -- | `claude-to-devin` | `claude-to-factory` |
163
+ | **Devin** | `devin-to-pi` | `devin-to-codex` | `devin-to-opencode` | `devin-to-claude` | -- | `devin-to-factory` |
164
+ | **Factory** | `factory-to-pi` | `factory-to-codex` | `factory-to-opencode` | `factory-to-claude` | `factory-to-devin` | -- |
165
+
166
+ ## How to list sessions
167
+
168
+ ```powershell
169
+ python -m unisessions list codex
170
+ python -m unisessions list pi
171
+ python -m unisessions list opencode
172
+ python -m unisessions list claude
173
+ python -m unisessions list devin
174
+ python -m unisessions list factory
175
+ ```
176
+
177
+ ## How to convert sessions
178
+
179
+ All commands default to dry-run. Add `--write` to produce output.
180
+
181
+ ```powershell
182
+ python -m unisessions codex-to-pi <session-id> --write
183
+ python -m unisessions pi-to-codex <session-id> --write
184
+ python -m unisessions codex-to-opencode <session-id> --write
185
+ python -m unisessions pi-to-opencode <session-id> --write
186
+ python -m unisessions opencode-to-codex <session-id> --write
187
+ python -m unisessions opencode-to-pi <session-id> --write
188
+ python -m unisessions claude-to-pi <session-id> --write
189
+ python -m unisessions pi-to-claude <session-id> --write
190
+ python -m unisessions claude-to-codex <session-id> --write
191
+ python -m unisessions codex-to-claude <session-id> --write
192
+ python -m unisessions claude-to-opencode <session-id> --write
193
+ python -m unisessions opencode-to-claude <session-id> --write
194
+ python -m unisessions devin-to-pi <session-id> --write
195
+ python -m unisessions pi-to-devin <session-id> --write
196
+ python -m unisessions devin-to-codex <session-id> --write
197
+ python -m unisessions codex-to-devin <session-id> --write
198
+ python -m unisessions devin-to-opencode <session-id> --write
199
+ python -m unisessions opencode-to-devin <session-id> --write
200
+ python -m unisessions devin-to-claude <session-id> --write
201
+ python -m unisessions claude-to-devin <session-id> --write
202
+ python -m unisessions factory-to-pi <session-id> --write
203
+ python -m unisessions pi-to-factory <session-id> --write
204
+ python -m unisessions factory-to-codex <session-id> --write
205
+ python -m unisessions codex-to-factory <session-id> --write
206
+ python -m unisessions factory-to-opencode <session-id> --write
207
+ python -m unisessions opencode-to-factory <session-id> --write
208
+ python -m unisessions factory-to-claude <session-id> --write
209
+ python -m unisessions claude-to-factory <session-id> --write
210
+ python -m unisessions factory-to-devin <session-id> --write
211
+ python -m unisessions devin-to-factory <session-id> --write
212
+ ```
213
+
214
+ ## How to export traces
215
+
216
+ Export any session as a trace file for HuggingFace Hub upload, model fine-tuning, or training data preparation. Three formats are supported:
217
+
218
+ | Format | Use case |
219
+ |---|---|
220
+ | `sts` | HuggingFace Hub trace viewer (Session Trace Simple Format) |
221
+ | `openai` | OpenAI / Azure fine-tuning JSONL format |
222
+ | `sharegpt` | ShareGPT format for LLaMA-Factory, Axolotl, torchtune |
223
+
224
+ ```powershell
225
+ # HuggingFace STS format (default) -- print to stdout
226
+ python -m unisessions to-trace codex <session-id> --format sts
227
+
228
+ # OpenAI fine-tuning format -- write to file
229
+ python -m unisessions to-trace pi <session-id> --format openai --write -o train.jsonl
230
+
231
+ # ShareGPT format from Devin session
232
+ python -m unisessions to-trace devin <session-id> --format sharegpt --write -o traces.jsonl
233
+ ```
234
+
235
+ Upload to HuggingFace Hub:
236
+
237
+ ```powershell
238
+ pip install huggingface-cli
239
+ hf upload your-username/your-dataset trace.jsonl
240
+ ```
241
+
242
+ The Hub auto-detects the trace format and renders it in the trace viewer. See the [trace export docs](docs/traces.md) for SDK usage and format details.
243
+
244
+ ## How to handle conflicts
245
+
246
+ When a destination file already exists use `--on-conflict` to control behavior:
247
+
248
+ | Mode | Behavior |
249
+ |---|---|
250
+ | `skip` (default) | Skip if destination exists |
251
+ | `overwrite` | Replace existing destination with new content |
252
+ | `fork` | Generate a new UUID session ID, preserve old file untouched |
253
+ | `update` | Skip if unchanged, overwrite if source changed (fast head-meta + line count check) |
254
+
255
+ ```powershell
256
+ python -m unisessions codex-to-pi <id> --write --on-conflict fork
257
+ python -m unisessions codex-to-pi <id> --write --on-conflict update
258
+ ```
259
+
260
+ ## How to bulk export
261
+
262
+ Export all Codex sessions to one or more targets in parallel:
263
+
264
+ ```powershell
265
+ python -m unisessions codex-to-pi-all --write --workers 8
266
+ python -m unisessions export-all --write --targets pi opencode claude devin factory --workers 8
267
+ ```
268
+
269
+ ## How to use custom paths
270
+
271
+ Use system defaults by omitting path flags. For backups or staging:
272
+
273
+ ```powershell
274
+ python -m unisessions --codex-session-dir C:\path\to\sessions list codex
275
+ python -m unisessions --pi-session-dir C:\path\to\pi\sessions list pi
276
+ python -m unisessions --opencode-session-dir C:\path\to\opencode\exports list opencode
277
+ python -m unisessions --claude-session-dir C:\path\to\claude\projects list claude
278
+ python -m unisessions --devin-session-dir C:\path\to\devin\transcripts list devin
279
+ python -m unisessions --factory-session-dir C:\path\to\factory\sessions list factory
280
+ ```
281
+
282
+ OpenCode output files use the official import/export JSON shape. Load them with
283
+ `opencode import <path-to-json>`.
284
+
285
+ ## MCP server for agent chat recall
286
+
287
+ UniSessions ships a [FastMCP](https://github.com/jlowin/fastmcp) server that
288
+ exposes a SQLite FTS5 full-text search index over parsed session chat history.
289
+ AI agents can use it to recall past conversations, find what was discussed, and
290
+ search across all providers.
291
+
292
+ ### Setup
293
+
294
+ ```powershell
295
+ python -m unisessions.mcp_server
296
+ ```
297
+
298
+ ### MCP client configuration
299
+
300
+ ```json
301
+ {
302
+ "mcpServers": {
303
+ "unisessions": {
304
+ "command": "unisessions-mcp",
305
+ "args": [],
306
+ "env": {
307
+ "UNISESSIONS_SEARCH_INDEX": "C:\\Users\\you\\AppData\\Local\\unisessions\\search.sqlite"
308
+ }
309
+ }
310
+ }
311
+ }
312
+ ```
313
+
314
+ ### HTTP transports for app-managed servers
315
+
316
+ ```powershell
317
+ unisessions-mcp --transport streamable-http --host 127.0.0.1 --port 8765 --path /mcp
318
+ unisessions-mcp --transport http --host 127.0.0.1 --port 8765
319
+ unisessions-mcp --transport sse --host 127.0.0.1 --port 8765
320
+ ```
321
+
322
+ Environment knobs: `UNISESSIONS_MCP_TRANSPORT`, `UNISESSIONS_MCP_HOST`,
323
+ `UNISESSIONS_MCP_PORT`, `UNISESSIONS_MCP_PATH`, `UNISESSIONS_MCP_LOG_LEVEL`,
324
+ `UNISESSIONS_MCP_SHOW_BANNER`, `UNISESSIONS_SEARCH_INDEX`.
325
+
326
+ ### MCP tools
327
+
328
+ | Tool | Description |
329
+ |---|---|
330
+ | `list_chats` | List sessions globally or filtered by provider and project path |
331
+ | `index_status` | Report indexed, missing, stale, deleted, and refresh-size counts |
332
+ | `refresh_chats_index` | Parse sessions into SQLite FTS5 index for fast recall |
333
+ | `search_chats` | Full-text search with literal, regex, all-keywords, and any-keywords modes |
334
+ | `search_sessions` | Find which sessions match a topic, with match counts and top snippets |
335
+
336
+ `search_chats` returns a structured response with `search_metadata` (total_matches, deduplicated, sessions_searched, messages_searched, truncated) and a `results` array ranked by relevance score. Duplicate messages across compaction cycles are collapsed to a single hit with a `duplicate_count` field.
337
+
338
+ `search_chats` supports provider (`codex`, `pi`, `opencode`, `claude`, `devin`, `factory`), cwd,
339
+ session_id, role (`user`, `assistant`), message type (`message`, `compaction`,
340
+ `contextual`), `exclude_keywords` to filter out false positives, `max_per_session`
341
+ (default 5) to prevent one session from flooding results, date range (`after`,
342
+ `before`), and stale-index policy (`refresh`, `skip`, `error`).
343
+
344
+ Search runs over parsed `TextMessage` rows, not raw JSON files, so semantic
345
+ filters like `roles=["user"]` stay correct. Tool calls and tool outputs are
346
+ excluded to keep recall focused on chat text. An internal raw-match cap of 200
347
+ prevents timeouts on massive sessions.
348
+
349
+ **Performance**: warm indexed search ~35-40ms on a 20-session corpus. Cold
350
+ index refresh ~39-49s (I/O-bound). Call `index_status` first, then
351
+ `refresh_chats_index`, then use `search_chats` with `stale_policy="skip"` for
352
+ fast interactive recall.
353
+
354
+ ## SDK usage
355
+
356
+ Build your own application on top of `session_sdk` without the CLI:
357
+
358
+ ```python
359
+ from session_sdk import (
360
+ CodexStore, PiStore, PiDcpStore, FactoryStore,
361
+ CodexToPiConverter, SessionIdFactory, WindowsDefaults,
362
+ )
363
+
364
+ defaults = WindowsDefaults()
365
+ codex = CodexStore(defaults.codex_home)
366
+ pi = PiStore(defaults.pi_agent_home)
367
+ dcp = PiDcpStore(defaults.pi_dcp_home)
368
+
369
+ converter = CodexToPiConverter(codex, pi, dcp, SessionIdFactory())
370
+ plan = converter.plan("your-session-id-here")
371
+
372
+ print(f"Source: {plan.source.path}")
373
+ print(f"Destination: {plan.destination}")
374
+ print(f"Records: {len(plan.records)}")
375
+
376
+ converter.write(plan, overwrite=False)
377
+ ```
378
+
379
+ ### Trace export API
380
+
381
+ ```python
382
+ from session_sdk import (
383
+ CodexStore, WindowsDefaults,
384
+ MessageExtractor, build_trace,
385
+ )
386
+ from session_sdk.jsonl import _dumps
387
+
388
+ defaults = WindowsDefaults()
389
+ store = CodexStore(defaults.codex_home)
390
+ session = store.load("session-id")
391
+ messages = MessageExtractor().from_codex(session)
392
+
393
+ # Build HuggingFace STS-format trace
394
+ records = build_trace("sts", session, messages)
395
+
396
+ # Write to JSONL
397
+ with open("trace.jsonl", "wb") as f:
398
+ for record in records:
399
+ f.write(_dumps(record))
400
+ f.write(b"\n")
401
+ ```
402
+
403
+ ### Search API
404
+
405
+ ```python
406
+ from session_sdk import (
407
+ CodexStore, PiStore, OpenCodeStore, ClaudeStore, DevinStore, FactoryStore,
408
+ SessionSearchEngine, WindowsDefaults,
409
+ )
410
+
411
+ defaults = WindowsDefaults()
412
+ engine = SessionSearchEngine(
413
+ CodexStore(defaults.codex_home),
414
+ PiStore(defaults.pi_agent_home),
415
+ OpenCodeStore(defaults.opencode_data_home),
416
+ claude=ClaudeStore(defaults.claude_home),
417
+ devin=DevinStore(defaults.devin_home),
418
+ factory=FactoryStore(defaults.factory_home),
419
+ )
420
+
421
+ engine.refresh_index(provider="claude")
422
+
423
+ response = engine.search(
424
+ query="authentication",
425
+ provider="claude",
426
+ roles=["assistant"],
427
+ stale_policy="skip",
428
+ )
429
+ for hit in response["results"]:
430
+ print(f"{hit['session_id']} [{hit['role']}] {hit['snippet'][:80]}")
431
+
432
+ # SDK escape hatch for apps that want custom ranking or filtering.
433
+ raw_rows = engine.raw_search_rows(query="authentication", provider="claude")
434
+
435
+ engine.close()
436
+ ```
437
+
438
+ ## Architecture
439
+
440
+ ```
441
+ session-export/
442
+ pyproject.toml # both packages + optional [mcp] extra
443
+ session_sdk/ # the SDK core (no CLI dependencies)
444
+ __init__.py # public API surface
445
+ json_types.py # JSON type guards and coercion
446
+ jsonl.py # JSONL read/write helpers (orjson when available)
447
+ models.py # SessionSummary, TextMessage, NativeSession, ConversionPlan
448
+ paths.py # WindowsDefaults, path encoding, SessionIdFactory, timestamps
449
+ stores.py # CodexStore, PiStore, PiDcpStore, OpenCodeStore, ClaudeStore, DevinStore, FactoryStore
450
+ converters.py # Extractors, builders, 30 converters
451
+ traces.py # STS, OpenAI, ShareGPT trace format builders
452
+ search.py # parsed SQLite FTS5 chat recall index/search
453
+ unisessions/ # CLI and MCP app (depends on session_sdk)
454
+ __init__.py
455
+ __main__.py # python -m unisessions
456
+ cli.py # argparse, command routing, dry-run/write, conflict resolution, trace export
457
+ mcp_server.py # FastMCP tools for chat recall/search
458
+ tests/
459
+ test_conversion.py # 29 tests
460
+ docs/ # full API documentation
461
+ examples/ # 7 tested Python example scripts
462
+ requirements.txt # tiktoken (required), orjson + google-re2 (optional)
463
+ requirements-mcp.txt # fastmcp for MCP server
464
+ ```
465
+
466
+ ### Dependency chain (no cycles)
467
+
468
+ ```
469
+ json_types (leaf)
470
+ jsonl -> json_types
471
+ models -> json_types
472
+ paths (leaf)
473
+ stores -> models, jsonl, json_types, paths
474
+ converters -> stores, models, paths, json_types
475
+ search -> stores, converters, models
476
+ ```
477
+
478
+ The SDK never imports from the CLI. `unisessions` depends on `session_sdk`,
479
+ never the reverse.
480
+
481
+ ## Default session paths
482
+
483
+ | Agent | Default Location |
484
+ |---|---|
485
+ | Codex sessions | `~/.codex/sessions` |
486
+ | Codex archived | `~/.codex/archived_sessions` |
487
+ | Pi sessions | `~/.pi/agent/sessions` |
488
+ | Pi DCP sidecars | `~/.pi-dcp/sessions` |
489
+ | OpenCode data | `%APPDATA%\opencode` or `OPENCODE_GLOBAL_DATA_DIR` |
490
+ | Claude Code | `~/.claude` or `CLAUDE_CONFIG_DIR` |
491
+ | Devin | `%APPDATA%/devin` or `DEVIN_CONFIG_DIR` |
492
+ | Factory | `~/.factory` or `FACTORY_CONFIG_DIR` |
493
+
494
+ ## Data fidelity
495
+
496
+ UniSessions performs text-history conversions, not full behavioral state
497
+ replay. It preserves user/assistant/system text and enough metadata for the
498
+ target tool to open the session. It does not fully preserve every tool call,
499
+ provider-specific event, approval state, sandbox state, MCP runtime, or
500
+ UI-only event.
501
+
502
+ ### How compaction is handled
503
+
504
+ Compaction markers are preserved across all six formats so the target tool
505
+ can reconstruct context correctly:
506
+
507
+ - **Pi**: `type="compaction"` entry with `summary`, `firstKeptEntryId`,
508
+ `tokensBefore`, `details`, and `fromHook=True`
509
+ - **Codex**: `type="compacted"` record with `payload.message` summary text
510
+ - **OpenCode**: user message with `CompactionPart` + assistant `summary=True`
511
+ - **Claude Code**: `system` entry with `subtype="compact_boundary"` +
512
+ `logicalParentUuid`, followed by user message with `isCompactSummary=true`
513
+ - **Devin**: compaction summaries become system steps in ATIF transcript JSON
514
+
515
+ ### How contextual messages are handled
516
+
517
+ Codex injects contextual messages (permissions, AGENTS.md instructions,
518
+ environment context, skills, plugins) as `developer` or `user` role messages.
519
+ These are marked `is_contextual=True` by the SDK extractor and skipped by all
520
+ builders during export to prevent payload overflow in target tools. SDK
521
+ consumers can still inspect these messages.
522
+
523
+ ## Performance
524
+
525
+ - `orjson` for JSON parsing when available (2x faster than stdlib)
526
+ - `google-re2` for regex search when available (4x faster than stdlib `re`)
527
+ - Trace export to HuggingFace STS, OpenAI fine-tuning, and ShareGPT formats
528
+ - O(1) session lookup via cached path index and ID index
529
+ - `has_changes()` reads head meta + line count (no full JSON parse)
530
+ - Bulk export reuses converter instances across sessions
531
+ - Default bulk workers: 8 (higher is opt-in; 32 workers measured ~2x slower)
532
+ - Warm indexed search: ~35-40ms on a 20-session corpus
533
+ - Cold index refresh: ~39-49s (I/O-bound, threading helps modestly)
534
+
535
+ ## FAQ
536
+
537
+ **Can I convert Claude Code sessions to Pi?**
538
+
539
+ Yes. Use `python -m unisessions claude-to-pi <session-id> --write`. All 30
540
+ conversion directions are supported between Codex, Pi, OpenCode, Claude Code,
541
+ Devin, and Factory.
542
+
543
+ **Can I export all my Codex sessions at once?**
544
+
545
+ Yes. Use `python -m unisessions codex-to-pi-all --write --workers 8` to bulk
546
+ export all Codex sessions to Pi in parallel. You can also export to multiple
547
+ targets at once with `export-all --write --targets pi opencode claude devin factory`.
548
+
549
+ **Can my AI agent search my old chat history?**
550
+
551
+ Yes. The MCP server exposes `search_chats` and `search_sessions` tools that do full-text search
552
+ over parsed chat messages from all providers. Your agent can recall what you
553
+ discussed in any session across any project. Search runs on a SQLite FTS5
554
+ index so warm queries are ~35ms. Results are ranked by relevance, deduplicated
555
+ across compaction cycles, and capped per session to prevent timeouts.
556
+
557
+ **What happens if the destination session already exists?**
558
+
559
+ Use `--on-conflict` to control behavior: `skip` (default), `overwrite`,
560
+ `fork` (new UUID, preserves old file), or `update` (skip if unchanged,
561
+ overwrite if source changed).
562
+
563
+ **Does this preserve tool calls and tool outputs?**
564
+
565
+ No. This tool performs text-history conversions preserving user and assistant
566
+ chat messages, compaction summaries, and session metadata. Tool calls and
567
+ tool outputs are not preserved in the current version.
568
+
569
+ **Can I use the SDK without the CLI?**
570
+
571
+ Yes. The SDK (`session_sdk`) is a standalone library with no CLI dependencies.
572
+ Import stores, converters, and the search engine directly in your own Python
573
+ projects. The CLI and MCP server are thin wrappers built on top.
574
+
575
+ **What session formats are supported?**
576
+
577
+ Codex JSONL rollout files, Pi JSONL append-only tree entries, OpenCode
578
+ export/import JSON, Claude Code JSONL transcript files, Devin ATIF
579
+ transcript JSON with SQLite metadata, and Factory JSONL transcript files.
580
+ All six formats are supported in all 30 conversion directions.
581
+
582
+ **How fast is bulk export?**
583
+
584
+ A full export of 276 Codex sessions to Pi completes in about 65 seconds with
585
+ 8 workers. The largest sessions (700MB+) take a few seconds each. Default
586
+ workers is 8 because higher counts measured slower on I/O-bound workloads.
587
+
588
+ ## Contributing
589
+
590
+ 1. Fork the repo
591
+ 2. Create a branch: `git checkout -b feature/your-feature`
592
+ 3. Run tests: `python -m unittest discover -s tests -v`
593
+ 4. Submit a PR with a description of your change
594
+
595
+ ## Development
596
+
597
+ ```powershell
598
+ python -m compileall session_sdk unisessions tests
599
+ python -m unittest discover -s tests -v
600
+ ```
601
+
602
+ 29 tests covering conversion shape, compaction extraction/emission, dry-run
603
+ safety, assistant usage estimation, OpenCode JSON shape, custom session
604
+ directories, path encoding, Claude extraction and conversion, Devin extraction
605
+ and conversion, trace format building (STS, OpenAI, ShareGPT), search behavior,
606
+ search index persistence, regex full-index search, keyword contraction
607
+ handling, and dedup edge cases.
608
+
609
+ ## Links
610
+
611
+ - X/Twitter: [@ImVibhek](https://x.com/ImVibhek)
612
+ - Website: [vibheksoni.com](https://vibheksoni.com/)
613
+ - Security Blog: [opendoors.wtf](https://opendoors.wtf/)
614
+
615
+ ## License
616
+
617
+ MIT