Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: CI

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

jobs:
python:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}
enable-cache: true
- run: uv sync --locked
- run: uv run ruff check .
- run: uv run ruff format --check src tests scripts
- run: uv run pytest -q
- run: uv build

website:
runs-on: ubuntu-latest
defaults:
run:
working-directory: website
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 22.13.0
cache: npm
cache-dependency-path: website/package-lock.json
- run: npm ci
- run: npm run lint
- run: npm test
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@ here. Native format compatibility is documented separately in

## Unreleased

## 0.9.0 - 2026-08-26

- Add Grok 1.0.5, Kilo Code 7.5.0, and OpenHands 1.16.0 as readable,
writable, discoverable, inspectable, searchable native session formats.
- Expand the symmetric matrix from 144 to 225 ordered routes, including
same-format portable rewrites for all three formats.
- Preserve ordered text, linked tools/results, and supported images; preserve
OpenHands condensations and flatten Grok summaries with explicit loss
accounting. Keep private thinking and native runtime state out of migrated
history.
- Prove all three generated sessions through their exact pinned Linux x64
binaries and a credential-free loopback model: each runtime loaded imported
context, continued the session, and retained the imported native prefix.
- Use only Kilo's official import/export commands and run import from the target
workspace to preserve its CWD. Work around Kilo 7.5.0's broken JSON list path
with a body-discarding official per-ID export collision probe.
- Add a website-hosted 15-agent logo grid to the README and landing page; no
third-party agent logo assets are added to the MIT Python repository.

- Add Oh My Pi (OMP) 18.0.5 as a readable, writable, discoverable,
inspectable, searchable native session format, including title-based lookup
and same-format portable rewrites.
Expand Down
45 changes: 29 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
<strong>GitHub Copilot CLI</strong>, <strong>Antigravity CLI</strong>,
<strong>Cursor Agent</strong>, <strong>Mistral Vibe</strong>,
<strong>Muse Code</strong>, <strong>Qwen Code</strong>, and
<strong>Kimi Code</strong>.
<strong>Kimi Code</strong>, <strong>Grok</strong>,
<strong>Kilo Code</strong>, and <strong>OpenHands</strong>.
</p>

## Install
Expand Down Expand Up @@ -95,20 +96,31 @@ The linked procedure is sandbox-tested with both Claude Code and Codex. See the

## Compatibility

- Claude Code
- Codex CLI
- Pi
- Oh My Pi (OMP)
- OpenCode
- GitHub Copilot CLI
- Antigravity CLI
- Mistral Vibe
- Muse Code
- Qwen Code
- Kimi Code
- Cursor Agent (experimental, pinned, text only)

Every listed format can be a source or target: 144 ordered routes, including
<table>
<tr>
<td align="center" width="20%"><a href="https://github.com/anthropics/claude-code"><img src="https://session-migrate.github.io/agents/claude-code.svg" width="64" height="64" alt="Claude Code logo"><br><strong>Claude Code</strong></a></td>
<td align="center" width="20%"><a href="https://github.com/openai/codex"><img src="https://session-migrate.github.io/agents/codex.svg" width="64" height="64" alt="Codex logo"><br><strong>Codex</strong></a></td>
<td align="center" width="20%"><a href="https://pi.dev"><img src="https://session-migrate.github.io/agents/pi.svg" width="64" height="64" alt="Pi logo"><br><strong>Pi</strong></a></td>
<td align="center" width="20%"><a href="https://github.com/can1357/oh-my-pi"><img src="https://session-migrate.github.io/agents/oh-my-pi.svg" width="64" height="64" alt="Oh My Pi logo"><br><strong>Oh My Pi</strong></a></td>
<td align="center" width="20%"><a href="https://github.com/anomalyco/opencode"><img src="https://session-migrate.github.io/agents/opencode.svg" width="64" height="64" alt="OpenCode logo"><br><strong>OpenCode</strong></a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/github/copilot-cli"><img src="https://session-migrate.github.io/agents/copilot.svg" width="64" height="64" alt="Copilot logo"><br><strong>Copilot</strong></a></td>
<td align="center"><a href="https://developers.google.com/antigravity"><img src="https://session-migrate.github.io/agents/antigravity.svg" width="64" height="64" alt="Antigravity logo"><br><strong>Antigravity</strong></a></td>
<td align="center"><a href="https://github.com/mistralai/mistral-vibe"><img src="https://session-migrate.github.io/agents/mistral-vibe.svg" width="64" height="64" alt="Mistral Vibe logo"><br><strong>Mistral Vibe</strong></a></td>
<td align="center"><a href="https://dev.meta.ai/"><img src="https://session-migrate.github.io/agents/muse.svg" width="64" height="64" alt="Muse Code logo"><br><strong>Muse Code</strong></a></td>
<td align="center"><a href="https://github.com/QwenLM/qwen-code"><img src="https://session-migrate.github.io/agents/qwen-code.svg" width="64" height="64" alt="Qwen Code logo"><br><strong>Qwen Code</strong></a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/MoonshotAI/kimi-cli"><img src="https://session-migrate.github.io/agents/kimi-code.svg" width="64" height="64" alt="Kimi Code logo"><br><strong>Kimi Code</strong></a></td>
<td align="center"><a href="https://github.com/xai-org/grok-build"><img src="https://session-migrate.github.io/agents/grok.svg" width="64" height="64" alt="Grok logo"><br><strong>Grok</strong></a></td>
<td align="center"><a href="https://github.com/Kilo-Org/kilocode"><img src="https://session-migrate.github.io/agents/kilo-code.svg" width="64" height="64" alt="Kilo Code logo"><br><strong>Kilo Code</strong></a></td>
<td align="center"><a href="https://github.com/All-Hands-AI/OpenHands"><img src="https://session-migrate.github.io/agents/openhands.svg" width="64" height="64" alt="OpenHands logo"><br><strong>OpenHands</strong></a></td>
<td align="center"><a href="https://cursor.com/cli"><img src="https://session-migrate.github.io/agents/cursor.svg" width="64" height="64" alt="Cursor logo"><br><strong>Cursor*</strong></a></td>
</tr>
</table>

Every listed format can be a source or target: 225 ordered routes, including
same-format portable rewrites. Cursor deliberately transfers only ordered
user/assistant text and is pinned to one exact Linux build; it is not a
vendor-supported import API. Same-format migration creates a new independent
Expand All @@ -123,7 +135,7 @@ session—it is not a byte-for-byte clone or a live sync.
| Images | ✓ / partial | Supported image blocks move; other media is format-dependent |
| Compaction summaries | ✓ / partial | Recreated where the target has a portable equivalent |
| Readable reasoning | Vibe-only portable rewrite | Vibe keeps its explicit readable field when rewritten to Vibe; other/private/signed traces never move |
| Session name, ID, and picker entry | Recreated | The target gets a new native identity and resume state |
| Session name, ID, and picker entry | ✓ / partial | The target gets a new native identity; OpenHands derives its picker title from the first user turn |
| Branches, forks, and subagents | Not flattened | Cataloged separately where detectable; migrate the parent session |
| Private or signed thinking | No | Model/provider-bound traces are deliberately omitted |
| Auth, hooks, policies, MCP, and runtime config | No | These remain with the source client |
Expand Down Expand Up @@ -158,6 +170,7 @@ resumable native session.
- [Experimental Cursor format](https://github.com/xhluca/session-migrate/blob/main/docs/cursor-format.md)
- [Mistral Vibe format](https://github.com/xhluca/session-migrate/blob/main/docs/vibe-format.md)
- [Muse, Qwen Code, and Kimi Code formats](https://github.com/xhluca/session-migrate/blob/main/docs/muse-qwen-kimi-formats.md)
- [Grok, Kilo Code, and OpenHands formats](https://github.com/xhluca/session-migrate/blob/main/docs/grok-kilo-openhands-formats.md)

The Antigravity and Cursor adapters are clean-room, unofficial, and
version-pinned. Their independently observed formats are published separately:
Expand Down
15 changes: 13 additions & 2 deletions docs/additional-target-formats.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Additional native formats

This document summarizes the ten adapters beyond the original Claude/Codex
This document summarizes the thirteen adapters beyond the original Claude/Codex
pair. All are readable sources, writable targets, searchable catalog formats,
and same-format portable-rewrite targets in `session-migrate` 0.8.0.
and same-format portable-rewrite targets in `session-migrate` 0.9.0.

| Format | Pinned build | Native import strategy | Support level |
| --- | --- | --- | --- |
Expand All @@ -16,6 +16,9 @@ and same-format portable-rewrite targets in `session-migrate` 0.8.0.
| Muse Code | `0.2.1` | Write durable native event stream | Stable pinned adapter |
| Qwen Code | `0.22.1` | Write project-scoped chat graph JSONL | Stable pinned adapter |
| Kimi Code | `0.38.0` | Write native state + main-agent wire journal | Stable pinned adapter |
| Grok | `1.0.5` | Write native ACP summary/update pair | Stable pinned adapter |
| Kilo Code | `7.5.0` | Official `export`/`import` CLI | Stable pinned adapter |
| OpenHands | `1.16.0` | Write native SDK event documents | Stable pinned adapter |

“Stable” here means the exact pinned version passed the documented native
oracle. It does not mean a vendor promises its private local format as an
Expand Down Expand Up @@ -48,6 +51,14 @@ opt-in real OpenRouter continuation that required the native model to recall a
marker found only in imported tool history. The default suite remains offline.
See [Muse, Qwen Code, and Kimi Code formats](muse-qwen-kimi-formats.md).

## Grok, Kilo Code, and OpenHands

Grok uses a paired summary/ACP update stream, Kilo uses its official
OpenCode-lineage import/export bundle, and OpenHands uses one validated SDK
event document per timeline item. Their exact binary pins, storage layouts,
loss accounting, and credential-free native continuation gates are documented
in [Grok, Kilo Code, and OpenHands formats](grok-kilo-openhands-formats.md).

## Shared contract

Every adapter:
Expand Down
49 changes: 32 additions & 17 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ conversation history, not an agent's entire runtime.

### JSON and JSONL sources

Claude, Codex, Pi, OMP, Copilot, Vibe, Muse, Qwen, and Kimi messages are bounded
Claude, Codex, Pi, OMP, Copilot, Vibe, Muse, Qwen, Kimi, Grok, and OpenHands
messages are bounded
JSON/line streams. Readers cap total
bytes, record bytes, record count, JSON nesting/nodes, and media payloads. They
validate source identity before and after reading so an actively appending,
Expand All @@ -62,13 +63,19 @@ replaced, or truncated file fails with a retryable error.
- Qwen follows the active UUID/parent chat graph and counts inactive branches.
- Kimi snapshots `state.json` and the main-agent protocol-`1.5` wire journal
together before projecting context events.
- Grok snapshots `summary.json` and its ACP `updates.jsonl` together, validates
the encoded workspace/UUID linkage, and projects messages, images, and tools.
- OpenHands coherently snapshots its ordered event files plus optional bounded
complete SDK base state, validates the event union and action linkage, and
projects messages, actions/observations, images, and condensations. Its native
picker title is the bounded first user text.

### OpenCode virtual sources
### OpenCode and Kilo virtual sources

The catalog reads only native session metadata from `opencode.db`. A selected
source is exported through exact pinned `opencode export`, parsed as an official
bundle, and represented by the virtual path `opencode:<id>`. The migrator never
queries message/part tables or writes OpenCode SQLite.
The catalog reads only native session metadata from `opencode.db` or `kilo.db`.
A selected source is exported through the exact pinned official CLI, parsed as
an official bundle, and represented by the virtual path `<format>:<id>`. The
migrator never queries message/part tables or writes either SQLite database.

### SQLite/protobuf sources

Expand Down Expand Up @@ -102,6 +109,9 @@ loss_counters)`. No writer reads another source format directly.
| Muse | Date-partitioned durable session event JSONL |
| Qwen | Project-scoped append-only chat graph JSONL |
| Kimi | Native `state.json` plus main-agent `wire.jsonl` session directory |
| Grok | Workspace-scoped `summary.json` plus ACP `updates.jsonl` |
| Kilo Code | Official JSON import bundle |
| OpenHands | Ordered SDK event JSON files in a conversation directory |

Every generated artifact is reparsed/validated before publication. Target
required IDs, timestamps, and metadata may be synthesized. Source tool output,
Expand Down Expand Up @@ -131,15 +141,17 @@ silently changed. The source is never overwritten.

- Claude/Codex/Pi/OMP write one native transcript and one manifest atomically.
- Muse/Qwen write one native transcript and one manifest atomically.
- Grok publishes its paired summary/update files and manifest with rollback guards.
- OpenHands publishes the complete event-file directory and manifest with rollback guards.
- Kimi reserves a native session directory and publishes its state, wire
journal, and manifest with rollback guards.
- Vibe reserves a short-ID-safe native directory and atomically publishes its
metadata, message stream, and manifest.
- Copilot reserves the complete session directory and writes events, workspace
sidecar, and manifest.
- OpenCode reserves a private external manifest, invokes only the official
pinned importer, confirms the ID through official listing, then finalizes the
manifest.
- OpenCode and Kilo reserve a private external manifest, invoke only the
official pinned importer, confirm the ID through official read/export
operations, then finalize the manifest.
- Antigravity and Cursor reserve the manifest, verify the exact pinned binary,
invoke their clean-room atomic database installers, validate the installed
session, then finalize the manifest.
Expand All @@ -149,14 +161,15 @@ that the session may already exist. Blind retry is intentionally avoided.

## Version boundaries

Claude/Codex writers are pinned to the local integration image; Pi, OMP, OpenCode,
Copilot, Antigravity, Cursor, Vibe, Muse, Qwen, and Kimi to exact host
Claude/Codex writers are pinned to the local integration image; Pi, OMP,
OpenCode, Copilot, Antigravity, Cursor, Vibe, Muse, Qwen, Kimi, Grok, Kilo, and
OpenHands to exact host
builds/releases. A source declaring a
different version produces `unvalidated_source_version`. A
`--target-cli-version` override changes metadata only and produces
`unvalidated_target_version`; it never changes writer architecture.

Automatic OpenCode, Antigravity, and Cursor installation is stricter: metadata
Automatic OpenCode, Kilo, Antigravity, and Cursor installation is stricter: metadata
overrides cannot bypass exact runtime version checks. Antigravity verifies its
binary digest. Cursor verifies launcher, main bundle, protobuf-bearing chunk,
bundled Node, sizes, SHA-256 values, and reported version.
Expand All @@ -176,17 +189,19 @@ Enumeration covers:
- Claude main sessions and nested sidechains;
- Codex active and archived rollouts;
- Pi and OMP workspace buckets, classified by their native heads;
- every OpenCode `session` row, including parents/archives;
- every OpenCode and Kilo `session` row, including parents/archives;
- Copilot session directories, including missing event logs;
- Antigravity conversation DBs; and
- Antigravity conversation DBs;
- Cursor workspace/chat DBs, including missing stores;
- Vibe and Kimi multi-file session directories;
- Muse date-partitioned event streams; and
- Qwen project chat graphs.
- Muse date-partitioned event streams;
- Qwen project chat graphs;
- Grok workspace session directories; and
- OpenHands conversation event directories.

JSONL rows use stat identity. Vibe and Kimi fingerprint both native files.
Antigravity/Cursor include DB/WAL/SHM fingerprints.
OpenCode rows use a fingerprint of every indexed metadata field. Unavailable
OpenCode and Kilo rows use a fingerprint of every indexed metadata field. Unavailable
roots retain prior rows instead of falsely marking everything missing.

Search covers native names/titles and IDs. Paths/CWDs are opt-in. “All sessions”
Expand Down
Loading