Install
$ agentstack add mcp-vibheksoni-session-export ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
UniSessions
UniSessions is an SDK-first AI CLI session converter for moving sessions between Codex, Claude Code, Pi, OpenCode, Devin, Factory, and Windsurf Cascade, 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, and Windsurf Cascade.
I use a lot of AI coding CLIs Codex Claude Code Pi OpenCode Devin Factory Windsurf and wanted to move a session from one tool into another without losing the useful conversation history
[](https://pypi.org/project/unisessions/) [](https://www.python.org/) []() [-purple)]() []() []() []() []() [](https://github.com/vibheksoni/session-export/stargazers)
Table of Contents
- [Why I built this](#why-i-built-this)
- [Quick Start](#quick-start)
- [Supported AI coding agents](#supported-ai-coding-agents)
- [All 42 conversion directions](#all-42-conversion-directions)
- [How to list sessions](#how-to-list-sessions)
- [How to convert sessions](#how-to-convert-sessions)
- [How to export traces](#how-to-export-traces)
- [How to handle conflicts](#how-to-handle-conflicts)
- [How to bulk export](#how-to-bulk-export)
- [How to use custom paths](#how-to-use-custom-paths)
- [MCP server for agent chat recall](#mcp-server-for-agent-chat-recall)
- [SDK usage](#sdk-usage)
- [Architecture](#architecture)
- [Default session paths](#default-session-paths)
- [Data fidelity](#data-fidelity)
- [Performance](#performance)
- [FAQ](#faq)
- [Contributing](#contributing)
- [Development](#development)
- [License](#license)
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 and Windsurf Cascade in any direction all 42 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
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
python -m unisessions codex-to-pi --write
python -m unisessions claude-to-pi --write
python -m unisessions devin-to-pi --write
python -m unisessions factory-to-pi --write
python -m unisessions windsurf-to-pi --write
Export a session as a HuggingFace trace:
python -m unisessions to-trace codex --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 |
All 42 conversion directions
| From \ To | Pi | Codex | OpenCode | Claude | Devin | Factory | Windsurf | |---|---|---|---|---|---|---|---| | Codex | codex-to-pi | -- | codex-to-opencode | codex-to-claude | codex-to-devin | codex-to-factory | codex-to-windsurf | | Pi | -- | pi-to-codex | pi-to-opencode | pi-to-claude | pi-to-devin | pi-to-factory | pi-to-windsurf | | OpenCode | opencode-to-pi | opencode-to-codex | -- | opencode-to-claude | opencode-to-devin | opencode-to-factory | opencode-to-windsurf | | Claude | claude-to-pi | claude-to-codex | claude-to-opencode | -- | claude-to-devin | claude-to-factory | claude-to-windsurf | | Devin | devin-to-pi | devin-to-codex | devin-to-opencode | devin-to-claude | -- | devin-to-factory | devin-to-windsurf | | Factory | factory-to-pi | factory-to-codex | factory-to-opencode | factory-to-claude | factory-to-devin | -- | factory-to-windsurf | | Windsurf | windsurf-to-pi | windsurf-to-codex | windsurf-to-opencode | windsurf-to-claude | windsurf-to-devin | windsurf-to-factory | -- |
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
How to convert sessions
All commands default to dry-run. Add --write to produce output.
python -m unisessions codex-to-pi --write
python -m unisessions pi-to-codex --write
python -m unisessions codex-to-opencode --write
python -m unisessions pi-to-opencode --write
python -m unisessions opencode-to-codex --write
python -m unisessions opencode-to-pi --write
python -m unisessions claude-to-pi --write
python -m unisessions pi-to-claude --write
python -m unisessions claude-to-codex --write
python -m unisessions codex-to-claude --write
python -m unisessions claude-to-opencode --write
python -m unisessions opencode-to-claude --write
python -m unisessions devin-to-pi --write
python -m unisessions pi-to-devin --write
python -m unisessions devin-to-codex --write
python -m unisessions codex-to-devin --write
python -m unisessions devin-to-opencode --write
python -m unisessions opencode-to-devin --write
python -m unisessions devin-to-claude --write
python -m unisessions claude-to-devin --write
python -m unisessions factory-to-pi --write
python -m unisessions pi-to-factory --write
python -m unisessions factory-to-codex --write
python -m unisessions codex-to-factory --write
python -m unisessions factory-to-opencode --write
python -m unisessions opencode-to-factory --write
python -m unisessions factory-to-claude --write
python -m unisessions claude-to-factory --write
python -m unisessions factory-to-devin --write
python -m unisessions devin-to-factory --write
python -m unisessions windsurf-to-pi --write
python -m unisessions pi-to-windsurf --write
python -m unisessions windsurf-to-codex --write
python -m unisessions codex-to-windsurf --write
python -m unisessions windsurf-to-opencode --write
python -m unisessions opencode-to-windsurf --write
python -m unisessions windsurf-to-claude --write
python -m unisessions claude-to-windsurf --write
python -m unisessions windsurf-to-devin --write
python -m unisessions devin-to-windsurf --write
python -m unisessions windsurf-to-factory --write
python -m unisessions factory-to-windsurf --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 --format sts
# OpenAI fine-tuning format -- write to file
python -m unisessions to-trace pi --format openai --write -o train.jsonl
# ShareGPT format from Devin session
python -m unisessions to-trace devin --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](docs/traces.md) 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 --write --on-conflict fork
python -m unisessions codex-to-pi --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 --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
OpenCode output files use the official import/export JSON shape. Load them with opencode import .
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": "C:\\Users\\you\\AppData\\Local\\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 (totalmatches, deduplicated, sessionssearched, 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), 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,
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=F
…
## Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [vibheksoni](https://github.com/vibheksoni)
- **Source:** [vibheksoni/session-export](https://github.com/vibheksoni/session-export)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.