Skip to main content

UniSessions

UniSessions is an SDK-first AI CLI session converter for moving sessions between Codex, Claude Code, Pi, OpenCode, Devin, Factory, Windsurf Cascade, Grok Build, and Freebuff Desktop, reading T3 Code threads too, with trace export for HuggingFace and fine-tuning, plus an MCP chat recall server built on top.

                                                                   
 ▄▄▄  ▄▄            ▄▄▄▄▄                                         
█▀██  ██           ██▀▀▀▀█▄                                       
  ██  ██  ▄     ▀▀ ▀██▄  ▄▀                   ▀▀       ▄          
  ██  ██  ████▄ ██   ▀██▄▄  ▄█▀█▄ ▄██▀█ ▄██▀█ ██ ▄███▄ ████▄ ▄██▀█
  ██  ██  ██ ██ ██ ▄   ▀██▄ ██▄█▀ ▀███▄ ▀███▄ ██ ██ ██ ██ ██ ▀███▄
  ▀█████▄▄██ ▀█▄██ ▀██████▀▄▀█▄▄▄█▄▄██▀█▄▄██▀▄██▄▀███▀▄██ ▀██▄▄██▀

Convert one AI CLI session format into another across Codex, Pi, OpenCode, Claude Code, Devin, Factory, Windsurf Cascade, Grok Build, and Freebuff Desktop.

I use a lot of AI coding CLIs Codex Claude Code Pi OpenCode Devin Factory Windsurf Grok and wanted to move a session from one tool into another without losing the useful conversation history

PyPI Python 3.11+ Tests Providers Conversions Traces MCP License GitHub stars


Table of Contents

Why I built this

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

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

So this does two things

  • Moves your sessions between Codex Pi OpenCode Claude Code Devin Factory Windsurf Cascade Grok Build and Freebuff Desktop in any direction all 72 combinations
  • Exports sessions as traces in HuggingFace STS OpenAI fine-tuning or ShareGPT format for Hub upload or model training
  • 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

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

Quick Start

Install from PyPI:

pip install unisessions
python -m unisessions list codex
python -m unisessions list pi
python -m unisessions list opencode
python -m unisessions list claude
python -m unisessions list devin
python -m unisessions list factory
python -m unisessions list windsurf
python -m unisessions list grok
python -m unisessions list freebuff
python -m unisessions list t3

Or clone the repo:

git clone https://github.com/vibheksoni/session-export.git
cd session-export
pip install -e .
python -m unisessions list codex

Convert a single session (dry-run first, then write):

python -m unisessions codex-to-pi <session-id>
python -m unisessions codex-to-pi <session-id> --write
python -m unisessions claude-to-pi <session-id> --write
python -m unisessions devin-to-pi <session-id> --write
python -m unisessions factory-to-pi <session-id> --write
python -m unisessions windsurf-to-pi <session-id> --write
python -m unisessions freebuff-to-pi <session-id> --write
python -m unisessions t3-to-pi <session-id> --write
python -m unisessions t3-to-codex <session-id> --write

Export a session as a HuggingFace trace:

python -m unisessions to-trace codex <session-id> --format sts --write -o trace.jsonl

Bulk export all Codex sessions to Pi:

python -m unisessions codex-to-pi-all --write --workers 8

Search across all sessions via MCP:

python -m unisessions.mcp_server

Supported AI coding agents

Agent Store Session Format Session IDs
OpenAI Codex codex JSONL rollout files under date tree UUID v7
Pi pi JSONL append-only tree entries in cwd-encoded dirs UUID v7
OpenCode opencode Official export/import JSON ses_ prefixed
Claude Code claude JSONL transcript files in cwd-sanitized dirs UUID v4
Devin (Windsurf CLI) devin ATIF transcript JSON + SQLite metadata slug names
Factory (Droid) factory JSONL transcript files with session headers UUID v4
Windsurf (Cascade) windsurf AES-256-GCM encrypted protobuf trajectory files UUID v4
Grok (Grok Build) grok ACP updates.jsonl + summary.json per session dir session directory name
Freebuff (Freebuff Desktop) freebuff Per-project SQLite desktop-v2.db (threads + messages) + project.json thread id
T3 Code t3 (source) and experimental target SQLite userdata/statev2.sqlite (legacy state.sqlite). Reads are read-only. thread id

All 72 conversion directions

T3 Code adds 18 directions, 90 in total. Reading T3 is stable: nine t3-to-<provider> commands. Writing into T3 is experimental: nine <provider>-to-t3 commands write a thread into a new, empty T3 home, which T3 imports the first time it starts there. The live T3 data directory is never written. See docs/stores.md.

From \ To Pi Codex OpenCode Claude Devin Factory Windsurf Grok Freebuff
Codex codex-to-pi -- codex-to-opencode codex-to-claude codex-to-devin codex-to-factory codex-to-windsurf codex-to-grok codex-to-freebuff
Pi -- pi-to-codex pi-to-opencode pi-to-claude pi-to-devin pi-to-factory pi-to-windsurf pi-to-grok pi-to-freebuff
OpenCode opencode-to-pi opencode-to-codex -- opencode-to-claude opencode-to-devin opencode-to-factory opencode-to-windsurf opencode-to-grok opencode-to-freebuff
Claude claude-to-pi claude-to-codex claude-to-opencode -- claude-to-devin claude-to-factory claude-to-windsurf claude-to-grok claude-to-freebuff
Devin devin-to-pi devin-to-codex devin-to-opencode devin-to-claude -- devin-to-factory devin-to-windsurf devin-to-grok devin-to-freebuff
Factory factory-to-pi factory-to-codex factory-to-opencode factory-to-claude factory-to-devin -- factory-to-windsurf factory-to-grok factory-to-freebuff
Windsurf windsurf-to-pi windsurf-to-codex windsurf-to-opencode windsurf-to-claude windsurf-to-devin windsurf-to-factory -- windsurf-to-grok windsurf-to-freebuff
Grok grok-to-pi grok-to-codex grok-to-opencode grok-to-claude grok-to-devin grok-to-factory grok-to-windsurf -- grok-to-freebuff
Freebuff freebuff-to-pi freebuff-to-codex freebuff-to-opencode freebuff-to-claude freebuff-to-devin freebuff-to-factory freebuff-to-windsurf freebuff-to-grok --

How to list sessions

python -m unisessions list codex
python -m unisessions list pi
python -m unisessions list opencode
python -m unisessions list claude
python -m unisessions list devin
python -m unisessions list factory
python -m unisessions list windsurf
python -m unisessions list grok
python -m unisessions list freebuff

How to convert sessions

All commands default to dry-run. Add --write to produce output.

python -m unisessions codex-to-pi <session-id> --write
python -m unisessions pi-to-codex <session-id> --write
python -m unisessions codex-to-opencode <session-id> --write
python -m unisessions pi-to-opencode <session-id> --write
python -m unisessions opencode-to-codex <session-id> --write
python -m unisessions opencode-to-pi <session-id> --write
python -m unisessions claude-to-pi <session-id> --write
python -m unisessions pi-to-claude <session-id> --write
python -m unisessions claude-to-codex <session-id> --write
python -m unisessions codex-to-claude <session-id> --write
python -m unisessions claude-to-opencode <session-id> --write
python -m unisessions opencode-to-claude <session-id> --write
python -m unisessions devin-to-pi <session-id> --write
python -m unisessions pi-to-devin <session-id> --write
python -m unisessions devin-to-codex <session-id> --write
python -m unisessions codex-to-devin <session-id> --write
python -m unisessions devin-to-opencode <session-id> --write
python -m unisessions opencode-to-devin <session-id> --write
python -m unisessions devin-to-claude <session-id> --write
python -m unisessions claude-to-devin <session-id> --write
python -m unisessions factory-to-pi <session-id> --write
python -m unisessions pi-to-factory <session-id> --write
python -m unisessions factory-to-codex <session-id> --write
python -m unisessions codex-to-factory <session-id> --write
python -m unisessions factory-to-opencode <session-id> --write
python -m unisessions opencode-to-factory <session-id> --write
python -m unisessions factory-to-claude <session-id> --write
python -m unisessions claude-to-factory <session-id> --write
python -m unisessions factory-to-devin <session-id> --write
python -m unisessions devin-to-factory <session-id> --write
python -m unisessions windsurf-to-pi <session-id> --write
python -m unisessions pi-to-windsurf <session-id> --write
python -m unisessions windsurf-to-codex <session-id> --write
python -m unisessions codex-to-windsurf <session-id> --write
python -m unisessions windsurf-to-opencode <session-id> --write
python -m unisessions opencode-to-windsurf <session-id> --write
python -m unisessions windsurf-to-claude <session-id> --write
python -m unisessions claude-to-windsurf <session-id> --write
python -m unisessions windsurf-to-devin <session-id> --write
python -m unisessions devin-to-windsurf <session-id> --write
python -m unisessions windsurf-to-factory <session-id> --write
python -m unisessions factory-to-windsurf <session-id> --write
python -m unisessions grok-to-pi <session-id> --write
python -m unisessions pi-to-grok <session-id> --write
python -m unisessions grok-to-codex <session-id> --write
python -m unisessions codex-to-grok <session-id> --write
python -m unisessions grok-to-opencode <session-id> --write
python -m unisessions opencode-to-grok <session-id> --write
python -m unisessions grok-to-claude <session-id> --write
python -m unisessions claude-to-grok <session-id> --write
python -m unisessions grok-to-devin <session-id> --write
python -m unisessions devin-to-grok <session-id> --write
python -m unisessions grok-to-factory <session-id> --write
python -m unisessions factory-to-grok <session-id> --write
python -m unisessions grok-to-windsurf <session-id> --write
python -m unisessions windsurf-to-grok <session-id> --write
python -m unisessions freebuff-to-pi <session-id> --write
python -m unisessions pi-to-freebuff <session-id> --write
python -m unisessions freebuff-to-codex <session-id> --write
python -m unisessions codex-to-freebuff <session-id> --write
python -m unisessions freebuff-to-opencode <session-id> --write
python -m unisessions opencode-to-freebuff <session-id> --write
python -m unisessions freebuff-to-claude <session-id> --write
python -m unisessions claude-to-freebuff <session-id> --write
python -m unisessions freebuff-to-devin <session-id> --write
python -m unisessions devin-to-freebuff <session-id> --write
python -m unisessions freebuff-to-factory <session-id> --write
python -m unisessions factory-to-freebuff <session-id> --write
python -m unisessions freebuff-to-windsurf <session-id> --write
python -m unisessions windsurf-to-freebuff <session-id> --write
python -m unisessions freebuff-to-grok <session-id> --write
python -m unisessions grok-to-freebuff <session-id> --write

How to export traces

Export any session as a trace file for HuggingFace Hub upload, model fine-tuning, or training data preparation. Three formats are supported:

Format Use case
sts HuggingFace Hub trace viewer (Session Trace Simple Format)
openai OpenAI / Azure fine-tuning JSONL format
sharegpt ShareGPT format for LLaMA-Factory, Axolotl, torchtune
# HuggingFace STS format (default) -- print to stdout
python -m unisessions to-trace codex <session-id> --format sts

# OpenAI fine-tuning format -- write to file
python -m unisessions to-trace pi <session-id> --format openai --write -o train.jsonl

# ShareGPT format from Devin session
python -m unisessions to-trace devin <session-id> --format sharegpt --write -o traces.jsonl

Upload to HuggingFace Hub:

pip install huggingface-cli
hf upload your-username/your-dataset trace.jsonl

The Hub auto-detects the trace format and renders it in the trace viewer. See the trace export docs for SDK usage and format details.

How to handle conflicts

When a destination file already exists use --on-conflict to control behavior:

Mode Behavior
skip (default) Skip if destination exists
overwrite Replace existing destination with new content
fork Generate a new UUID session ID, preserve old file untouched
update Skip if unchanged, overwrite if source changed (fast head-meta + line count check)
python -m unisessions codex-to-pi <id> --write --on-conflict fork
python -m unisessions codex-to-pi <id> --write --on-conflict update

How to bulk export

Export all Codex sessions to one or more targets in parallel:

python -m unisessions codex-to-pi-all --write --workers 8
python -m unisessions export-all --write --targets pi opencode claude devin factory windsurf grok freebuff --workers 8

How to use custom paths

Use system defaults by omitting path flags. For backups or staging:

python -m unisessions --codex-session-dir C:\path\to\sessions list codex
python -m unisessions --pi-session-dir C:\path\to\pi\sessions list pi
python -m unisessions --opencode-session-dir C:\path\to\opencode\exports list opencode
python -m unisessions --claude-session-dir C:\path\to\claude\projects list claude
python -m unisessions --devin-session-dir C:\path\to\devin\transcripts list devin
python -m unisessions --factory-session-dir C:\path\to\factory\sessions list factory
python -m unisessions --windsurf-session-dir C:\path\to\windsurf\cascade list windsurf
python -m unisessions --grok-home C:\path\to\grok --grok-session-dir C:\path\to\grok\sessions list grok
python -m unisessions --freebuff-home C:\path\to\freebuff --freebuff-session-dir C:\path\to\freebuff\projects list freebuff

OpenCode output files use the official import/export JSON shape. Load them with opencode import <path-to-json>.

MCP server for agent chat recall

UniSessions ships a FastMCP server that exposes a SQLite FTS5 full-text search index over parsed session chat history. AI agents can use it to recall past conversations, find what was discussed, and search across all providers.

Setup

python -m unisessions.mcp_server

MCP client configuration

{
  "mcpServers": {
    "unisessions": {
      "command": "unisessions-mcp",
      "args": [],
      "env": {
        "UNISESSIONS_SEARCH_INDEX": "%LOCALAPPDATA%\\unisessions\\search.sqlite"
      }
    }
  }
}

HTTP transports for app-managed servers

unisessions-mcp --transport streamable-http --host 127.0.0.1 --port 8765 --path /mcp
unisessions-mcp --transport http --host 127.0.0.1 --port 8765
unisessions-mcp --transport sse --host 127.0.0.1 --port 8765

Environment knobs: UNISESSIONS_MCP_TRANSPORT, UNISESSIONS_MCP_HOST, UNISESSIONS_MCP_PORT, UNISESSIONS_MCP_PATH, UNISESSIONS_MCP_LOG_LEVEL, UNISESSIONS_MCP_SHOW_BANNER, UNISESSIONS_SEARCH_INDEX.

MCP tools

Tool Description
list_chats List sessions globally or filtered by provider and project path
index_status Report indexed, missing, stale, deleted, and refresh-size counts
refresh_chats_index Parse sessions into SQLite FTS5 index for fast recall
search_chats Full-text search with literal, regex, all-keywords, and any-keywords modes
search_sessions Find which sessions match a topic, with match counts and top snippets

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.

search_chats supports provider (codex, pi, opencode, claude, devin, factory, windsurf, grok, freebuff, t3), cwd, session_id, role (user, assistant), message type (message, compaction, contextual), exclude_keywords to filter out false positives, max_per_session (default 5) to prevent one session from flooding results, date range (after, before), and stale-index policy (refresh, skip, error).

Search runs over parsed TextMessage rows, not raw JSON files, so semantic filters like roles=["user"] stay correct. Tool calls and tool outputs are excluded to keep recall focused on chat text. An internal raw-match cap of 200 prevents timeouts on massive sessions.

Performance: warm indexed search ~35-40ms on a 20-session corpus. Cold index refresh ~39-49s (I/O-bound). Call index_status first, then refresh_chats_index, then use search_chats with stale_policy="skip" for fast interactive recall.

SDK usage

Build your own application on top of session_sdk without the CLI:

from session_sdk import (
    CodexStore, PiStore, PiDcpStore, FactoryStore, WindsurfStore,
    CodexToPiConverter, SessionIdFactory, WindowsDefaults,
)

defaults = WindowsDefaults()
codex = CodexStore(defaults.codex_home)
pi = PiStore(defaults.pi_agent_home)
dcp = PiDcpStore(defaults.pi_dcp_home)

converter = CodexToPiConverter(codex, pi, dcp, SessionIdFactory())
plan = converter.plan("your-session-id-here")

print(f"Source:      {plan.source.path}")
print(f"Destination: {plan.destination}")
print(f"Records:     {len(plan.records)}")

converter.write(plan, overwrite=False)

Trace export API

from session_sdk import (
    CodexStore, WindowsDefaults,
    MessageExtractor, build_trace,
)
from session_sdk.jsonl import _dumps

defaults = WindowsDefaults()
store = CodexStore(defaults.codex_home)
session = store.load("session-id")
messages = MessageExtractor().from_codex(session)

# Build HuggingFace STS-format trace
records = build_trace("sts", session, messages)

# Write to JSONL
with open("trace.jsonl", "wb") as f:
    for record in records:
        f.write(_dumps(record))
        f.write(b"\n")

Search API

from session_sdk import (
    CodexStore, PiStore, OpenCodeStore, ClaudeStore, DevinStore, FactoryStore, WindsurfStore, GrokStore, FreebuffStore,
    SessionSearchEngine, WindowsDefaults,
)

defaults = WindowsDefaults()
engine = SessionSearchEngine(
    CodexStore(defaults.codex_home),
    PiStore(defaults.pi_agent_home),
    OpenCodeStore(defaults.opencode_data_home),
    claude=ClaudeStore(defaults.claude_home),
    devin=DevinStore(defaults.devin_home),
    factory=FactoryStore(defaults.factory_home),
    windsurf=WindsurfStore(defaults.windsurf_home),
    grok=GrokStore(defaults.grok_home),
    freebuff=FreebuffStore(defaults.freebuff_home),
)

engine.refresh_index(provider="claude")

response = engine.search(
    query="authentication",
    provider="claude",
    roles=["assistant"],
    stale_policy="skip",
)
for hit in response["results"]:
    print(f"{hit['session_id']} [{hit['role']}] {hit['snippet'][:80]}")

# SDK escape hatch for apps that want custom ranking or filtering.
raw_rows = engine.raw_search_rows(query="authentication", provider="claude")

engine.close()

Architecture

session-export/
  pyproject.toml              # both packages + optional [mcp] extra
  session_sdk/                # the SDK core (no CLI dependencies)
    __init__.py               # public API surface
    json_types.py             # JSON type guards and coercion
    jsonl.py                  # JSONL read/write helpers (orjson when available)
    models.py                 # SessionSummary, TextMessage, NativeSession, ConversionPlan
    paths.py                  # WindowsDefaults, path encoding, SessionIdFactory, timestamps
    stores.py                 # CodexStore, PiStore, PiDcpStore, OpenCodeStore, ClaudeStore, DevinStore, FactoryStore, WindsurfStore, GrokStore, FreebuffStore, T3Store (read; experimental write)
    converters.py             # Extractors, builders, 72 converters
    traces.py                 # STS, OpenAI, ShareGPT trace format builders
    search.py                 # parsed SQLite FTS5 chat recall index/search
  unisessions/                # CLI and MCP app (depends on session_sdk)
    __init__.py
    __main__.py               # python -m unisessions
    cli.py                    # argparse, command routing, dry-run/write, conflict resolution, trace export
    mcp_server.py             # FastMCP tools for chat recall/search
  tests/
    test_conversion.py        # 40 tests
  docs/                       # full API documentation
  examples/                   # 7 tested Python example scripts
  requirements.txt            # tiktoken + cryptography (required), orjson + google-re2 (optional)
  requirements-mcp.txt        # fastmcp for MCP server

Dependency chain (no cycles)

json_types  (leaf)
jsonl       -> json_types
models      -> json_types
paths       (leaf)
stores      -> models, jsonl, json_types, paths
converters  -> stores, models, paths, json_types
search      -> stores, converters, models

The SDK never imports from the CLI. unisessions depends on session_sdk, never the reverse.

Default session paths

Agent Default Location
Codex sessions ~/.codex/sessions
Codex archived ~/.codex/archived_sessions
Pi sessions ~/.pi/agent/sessions
Pi DCP sidecars ~/.pi-dcp/sessions
OpenCode data %APPDATA%\opencode or OPENCODE_GLOBAL_DATA_DIR
Claude Code ~/.claude or CLAUDE_CONFIG_DIR
Devin %APPDATA%/devin or DEVIN_CONFIG_DIR
Factory ~/.factory or FACTORY_CONFIG_DIR
Windsurf Cascade ~/.codeium/windsurf/cascade/ or WINDSURF_CONFIG_DIR
Grok Build $GROK_HOME/sessions or ~/.grok/sessions
Freebuff Desktop $FREEBUFF_CONFIG_DIR/projects or ~/.config/freebuff-desktop/projects
T3 Code $T3CODE_HOME/userdata or ~/.t3/userdata (statev2.sqlite, then legacy state.sqlite). Writes need an explicit --t3-home

Data fidelity

UniSessions performs text-history conversions, not full behavioral state replay. It preserves user/assistant/system text and enough metadata for the target tool to open the session. It does not fully preserve every tool call, provider-specific event, approval state, sandbox state, MCP runtime, or UI-only event.

How compaction is handled

Compaction markers are preserved across all nine formats so the target tool can reconstruct context correctly:

  • Pi: type="compaction" entry with summary, firstKeptEntryId, tokensBefore, details, and fromHook=True
  • Codex: type="compacted" record with payload.message summary text
  • OpenCode: user message with CompactionPart + assistant summary=True
  • Claude Code: system entry with subtype="compact_boundary" + logicalParentUuid, followed by user message with isCompactSummary=true
  • Devin: compaction summaries become system steps in ATIF transcript JSON
  • Windsurf Cascade: compaction checkpoints (field 30) become compaction summary messages
  • Grok Build: compaction summaries import as user_message_chunk envelopes so the conversation stays readable in Grok's TUI

How contextual messages are handled

Codex injects contextual messages (permissions, AGENTS.md instructions, environment context, skills, plugins) as developer or user role messages. These are marked is_contextual=True by the SDK extractor and skipped by all builders during export to prevent payload overflow in target tools. SDK consumers can still inspect these messages.

Performance

  • orjson for JSON parsing when available (2x faster than stdlib)
  • google-re2 for regex search when available (4x faster than stdlib re)
  • Trace export to HuggingFace STS, OpenAI fine-tuning, and ShareGPT formats
  • O(1) session lookup via cached path index and ID index
  • has_changes() reads head meta + line count (no full JSON parse)
  • Bulk export reuses converter instances across sessions
  • Default bulk workers: 8 (higher is opt-in; 32 workers measured ~2x slower)
  • Warm indexed search: ~35-40ms on a 20-session corpus
  • Cold index refresh: ~39-49s (I/O-bound, threading helps modestly)

FAQ

Can I convert Claude Code sessions to Pi?

Yes. Use python -m unisessions claude-to-pi <session-id> --write. All 72 conversion directions are supported between Codex, Pi, OpenCode, Claude Code, Devin, Factory, Windsurf Cascade, Grok Build, and Freebuff Desktop.

Can I export all my Codex sessions at once?

Yes. Use python -m unisessions codex-to-pi-all --write --workers 8 to bulk export all Codex sessions to Pi in parallel. You can also export to multiple targets at once with export-all --write --targets pi opencode claude devin factory windsurf grok freebuff.

Can my AI agent search my old chat history?

Yes. The MCP server exposes search_chats and search_sessions tools that do full-text search over parsed chat messages from all providers. Your agent can recall what you discussed in any session across any project. Search runs on a SQLite FTS5 index so warm queries are ~35ms. Results are ranked by relevance, deduplicated across compaction cycles, and capped per session to prevent timeouts.

What happens if the destination session already exists?

Use --on-conflict to control behavior: skip (default), overwrite, fork (new UUID, preserves old file), or update (skip if unchanged, overwrite if source changed).

Does this preserve tool calls and tool outputs?

No. This tool performs text-history conversions preserving user and assistant chat messages, compaction summaries, and session metadata. Tool calls and tool outputs are not preserved in the current version.

Can I use the SDK without the CLI?

Yes. The SDK (session_sdk) is a standalone library with no CLI dependencies. Import stores, converters, and the search engine directly in your own Python projects. The CLI and MCP server are thin wrappers built on top.

What session formats are supported?

Codex JSONL rollout files, Pi JSONL append-only tree entries, OpenCode export/import JSON, Claude Code JSONL transcript files, Devin ATIF transcript JSON with SQLite metadata, Factory JSONL transcript files, Windsurf Cascade AES-256-GCM encrypted protobuf trajectory files, Grok Build ACP updates.jsonl + summary.json session directories, and Freebuff Desktop per-project SQLite desktop-v2.db (threads + messages) databases. All nine formats are supported in all 72 conversion directions.

How fast is bulk export?

A full export of 276 Codex sessions to Pi completes in about 65 seconds with 8 workers. The largest sessions (700MB+) take a few seconds each. Default workers is 8 because higher counts measured slower on I/O-bound workloads.

Contributing

  1. Fork the repo
  2. Create a branch: git checkout -b feature/your-feature
  3. Run tests: python -m unittest discover -s tests -v
  4. Submit a PR with a description of your change

Development

python -m compileall session_sdk unisessions tests
python -m unittest discover -s tests -v

40 tests covering conversion shape, compaction extraction/emission, dry-run safety, assistant usage estimation, OpenCode JSON shape, custom session directories, path encoding, Claude extraction and conversion, Devin extraction and conversion, Windsurf Cascade extraction and conversion, Grok Build extraction, conversion, and store round-trips, Freebuff Desktop extraction, conversion, and store round-trips, trace format building (STS, OpenAI, ShareGPT), search behavior, search index persistence, regex full-index search, keyword contraction handling, and dedup edge cases.

License

MIT

Metadata

Release files for unisessions 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for unisessions 0.3.0
File Size Uploaded
unisessions-0.3.0.tar.gz 115.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for unisessions 0.3.0
File Interpreter ABI Platform
unisessions-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 199.6 kB

Release files / unisessions-0.3.0.tar.gz

Download URL unisessions-0.3.0.tar.gz
Size 115.3 kB
Tags Source
SHA-256 checksum
How to use checksums
5c3649581ea9b6ddd4e9121c129bdab8d90dfd6e46a2b9d026a54eb050e8b58f
BLAKE2b-256 checksum
How to use checksums
be3983c228fb1f49eca154983c210c22b8e3bc2fab03c3075a8de6e87baca982
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 Oct 8, 2026.

Transparency log

Release files / unisessions-0.3.0-py3-none-any.whl

Download URL unisessions-0.3.0-py3-none-any.whl
Size 84.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7213b2d53e93f473498494dddef62603212bb7d84d545a2e10d106ca574f9c2d
BLAKE2b-256 checksum
How to use checksums
0a1f89372d230d633f32b51490897592037c6b283eb59d63094f9d835ff320be
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 Oct 8, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page