Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
77c28e4
feat(antigravity): add Antigravity Desktop session migration support
elijahr Sep 29, 2026
acfce7a
feat(antigravity-desktop): add cross-platform path resolution and pla…
elijahr Sep 29, 2026
d87b215
fix(antigravity-desktop): correct language_server location to resourc…
elijahr Sep 29, 2026
b3fd43d
feat(antigravity-desktop): pin binary specifications for macOS, Linux…
elijahr Sep 29, 2026
9a420d8
fix(antigravity-desktop): bump module docstring version and include A…
elijahr Sep 29, 2026
59f2900
docs(antigravity-desktop): align format documentation name and invoca…
elijahr Sep 29, 2026
9b7a67c
docs(antigravity-desktop): structure format doc to mirror antigravity…
elijahr Sep 29, 2026
fa8f8ab
docs: normalize Antigravity Desktop version to 2.18.1
elijahr Sep 29, 2026
15ad3fb
fix(antigravity): resolve Windows SQLite locks, directory fsync, and …
gabszap Oct 2, 2026
18800d6
feat(hermes): pin the adapter to Hermes Agent 0.22.2 and SQLite schem…
gabszap Oct 16, 2026
95093d0
fix(hermes): resolve the 0.22.2 runtime instead of a launcher shebang
gabszap Oct 16, 2026
bebb9f7
fix(windows): release the manifest identity guard before a rollback u…
gabszap Oct 16, 2026
a0eaeba
fix(catalog): fold unsigned Windows stat identity into SQLite's signe…
gabszap Oct 16, 2026
299a8c6
docs(hermes): document the 0.22.2 pin, runtime resolution, and Window…
gabszap Oct 16, 2026
5a6cfc6
fix(hermes): install untitled instead of refusing a duplicate target …
gabszap Oct 16, 2026
ffd5b8d
docs(hermes): state where a dropped target title is reported
gabszap Oct 16, 2026
071536d
fix(hermes): carry the import bundle as UTF-8 bytes, not locale text
gabszap Oct 16, 2026
b78a14d
fix(hermes): resolve the native home the way the CLI does
gabszap Oct 16, 2026
1ae6d00
release: bump to 0.12.0
gabszap Oct 16, 2026
8cace03
fix(claude): accept the 2.1.300 compaction loop instead of refusing it
gabszap Oct 16, 2026
fd143b0
docs(claude): describe the compaction shape as per-event, not per-build
gabszap Oct 16, 2026
0b0f7cd
fix(hermes): raise the per-session import budget the store caps at 5 MiB
gabszap Oct 16, 2026
ac786ac
release: 0.12.1
gabszap Oct 16, 2026
d4553ae
style(hermes): satisfy the ruff check and format gates
gabszap Oct 16, 2026
fc1350d
test(native): pin the exact Hermes client to 0.22.2
gabszap Oct 16, 2026
6a82466
fix(hermes): recognize the 0.22.2 capture schema in the sanitizer
gabszap Oct 17, 2026
8c2c2dd
test(hermes): promote the 0.22.2 native corpus fixture
gabszap Oct 17, 2026
cda5bbe
fix(ci): align the exact-client install and the catalog fixture with …
gabszap Oct 17, 2026
502f4f2
docs(native-corpus): state the promoted Hermes 0.22.2 capture
gabszap Oct 17, 2026
16c623d
fix(native): reconstruct the pinned Hermes checkout on CI
gabszap Oct 17, 2026
6dbfdab
fix(native): replay the imported history, not the title-generation call
gabszap Oct 17, 2026
92ba62a
feat(opencode): support public v2 session transfers
tudstudent Oct 7, 2026
e859baa
fix(opencode): preserve history around private checkpoints and accoun…
tudstudent Oct 7, 2026
0fa6135
fix(opencode): report the selected schema validation release
tudstudent Oct 7, 2026
71bc9dd
fix(opencode): retain streamed input and validate pinned v2 native ro…
tudstudent Oct 9, 2026
03a6cde
fix(opencode): incorporate reviewed v2 transfer corrections
tudstudent Oct 12, 2026
b476046
docs(changelog): move the OpenCode v2 entry into its own Unreleased s…
gabszap Oct 16, 2026
62598d2
fix(windows): release the opencode manifest guard before the rollback…
gabszap Oct 16, 2026
88f452a
fix(opencode): resolve router-mirrored models as the target provider
gabszap Oct 17, 2026
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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ jobs:
- muse
- omp
- opencode
- opencode-v2
- openhands
- pi
- qwen
Expand Down
60 changes: 60 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,66 @@ here. Native format compatibility is documented separately in

## Unreleased

- Add version-aware OpenCode 2.0 public session transfer support, retaining the
legacy 1.17.20 adapter and native no-overwrite/dry-run controls. Preserve
portable tools, inline media, and completed compaction summaries, and account
for incomplete tools and provider-private state.

## 0.12.1 - 2026-10-16

- Accept the compaction loop Claude Code records when the compact summary is not
the boundary's direct child. The declaration is unchanged, but how many
attachment records the CLI interleaves varies, so the summary can sit three or
four parent hops below its boundary, and `preservedMessages` also names ids
from the summarized branch that are no longer on the active path. A readable
73 MB transcript with two compactions was refused as `Claude active graph
contains an ancestry cycle`; the loop is now validated as declared (the tail
walks up to the summary, the summary up to the boundary, every hop already on
the walked path) and a declaration that does not close still fails.
- Import a bundle the target store caps at 5 MiB per session by raising the
budget to what the bundle needs — never past the 25 MiB that store's own web
import accepts — and reporting `target_import_budget_raised` in the manifest.
A session carrying pasted screenshots (inline base64 images) produced a
6.88 MB bundle and was refused with `session exceeds the import size limit`,
although the store keeps that content.

## 0.12.0 - 2026-10-16

- Resolve the Hermes home the way the CLI does: `HERMES_HOME` when set,
otherwise `%LOCALAPPDATA%\hermes` on Windows and `~/.hermes` elsewhere. A bare
`~/.hermes` on Windows named a directory the CLI never writes to, so
`--to hermes` (and catalog discovery) missed the real store unless the caller
exported `HERMES_HOME` by hand.
- Move the Hermes import bundle across the process boundary as UTF-8 bytes
(`sys.stdin.buffer`, explicit stdout/stderr decoding, `-X utf8` child) instead
of locale-encoded text. On a Windows console whose code page is not UTF-8 the
old path replaced every non-ASCII character in the imported conversation —
title and message bodies — with `U+FFFD`.
- Install a Hermes session untitled instead of refusing the migration when the
target store already holds that title: Hermes enforces a partial unique index
over non-null titles, and its own importer treats the field as cosmetic. The
omission is counted as `title:duplicate_in_target` and reported as a
`target_title_omitted` manifest warning.
- Promote the Hermes Agent adapter to 0.22.2 (tag `v2026.9.24`) and SQLite
schema 31, keeping `SessionDB.import_sessions` as the native write boundary.
- Resolve the 0.22.2 runtime through `hermes --print-runtime-command` and
reproduce the launcher's `hermes_bootstrap` prelude, so the installer works
with a store Python that ships without third-party packages. The install root
comes from `hermes --version` (or the launcher's own bootstrap), and the
launcher shebang remains the fallback for builds predating the flag.
- Fix Hermes installation on Windows: keep the Windows essentials in the
sanitized child environment, initialize a missing `state.db` through the
native `SessionDB` constructor, and close the manifest identity guard before a
rollback unlinks it (`WinError 32`).
- Add first-class support for Antigravity Desktop (macOS/Electron) 2.18.1
with bidirectional conversion, SQLite schema adaptation, Hub Summaries
Protobuf cache synchronization (`agyhub_summaries_proto.pb`), project-scoped
sidebar discovery, and verified native Go language server integration.
- Document the clean-room Antigravity Desktop storage architecture, Protobuf
wire formats, Connect-RPC interfaces, and collision invariants in
`docs/antigravity-desktop-format.md`.


## 0.11.0 - 2026-09-11

- Read root Codex rollouts written with `history_mode: "paginated"` by using
Expand Down
189 changes: 189 additions & 0 deletions docs/antigravity-desktop-format.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# Antigravity Desktop session format

`session-migrate` supports Antigravity Desktop (macOS, Linux, and Windows)
through a clean-room adapter pinned to the 2.18.1 release:

| Property | Pinned value |
| --- | --- |
| Application | Antigravity Desktop `2.18.1` (Electron `44.3.0`) |
| macOS arm64 binary | `148,990,608` bytes, SHA-256 `300ee20f3108a511be1149602b91ba84cbbdcc42213067151e255584129be30f` |
| Linux x64 binary | `181,432,528` bytes, SHA-256 `ab4937445fa3817bc374a1db71062de7daecdb093cbfb6bd36b80f443198670e` |
| Windows x64 binary | `163,640,320` bytes, SHA-256 `1ed84e6a1d1e51064d80c9f382ab3a519eb2775cb91d552c63064a18cfdf3cf2` |
| Conversation store | `<home>/.gemini/antigravity/conversations/<uuid>.db` |
| Picker index | `<home>/.gemini/antigravity/conversation_summaries.db` (`PRAGMA user_version = 3`) |
| Hub summary cache | `<home>/.gemini/antigravity/agyhub_summaries_proto.pb` |
| UI project catalog | `<home>/.gemini/config/projects/<id>.json` + `app_storage.json` |

This is deliberately not a claim of compatibility with unreleased or arbitrary
Antigravity versions. Automatic installation checks executable digests and
schema invariants when native verification is requested.

No vendor code, binaries, descriptors, credentials, or user transcripts are
included in this repository. All schemas, wire mappings, and RPC endpoints were
established through clean-room differential probing and synthetic test fixtures.

## How the format was established

The adapter was derived from independent observations of synthetic sessions and
package analysis across macOS, Linux, and Windows distributions:

1. generate synthetic conversations with unique marker text in isolated environments;
2. inspect SQLite schema, columns, and Protobuf wire field numbers and types;
3. analyze Electron application resources (`app.asar`), verifying identical JavaScript
(`3c03ce352dc3c1b43f357c27ead1f73c74d198a8ded89b1b3d6a2539e7a6ac5c`) across all three OSes;
4. inspect native Go language server (`language_server`) symbols and Connect-RPC endpoints;
5. verify round-trip serialization and cold-reload step retrieval via Connect-RPC
(`GetCascadeTrajectorySteps`); and
6. test real-world conversation migration end-to-end with active multi-turn sessions.

## SQLite layout

Each conversation is stored as an independent SQLite 3 database with write-ahead
logging (`WAL`) containing these tables:

```text
trajectory_meta
steps
gen_metadata
executor_metadata
parent_references
trajectory_metadata_blob
battle_mode_infos
```

While the table names match Antigravity CLI, Desktop enforces distinct wire and
metadata invariants:

| Property | Antigravity CLI (`antigravity`) | Antigravity Desktop (`antigravity-desktop`) |
| --- | --- | --- |
| App data subdirectory | `~/.gemini/antigravity-cli` | `~/.gemini/antigravity` |
| `trajectory_meta.source` | `17` (`CLI`) | `1` (`IDE` / `Hub`) |
| `trajectory_metadata_blob` project ID | `"default-cli-project"` | `"outside-of-project"` (or workspace UUID) |
| `conversation_summaries.source` | `"antigravity-cli"` | `""` (empty string) |
| `conversation_summaries.app_data_dir` | `"antigravity-cli"` | `"antigravity"` |
| `conversation_summaries.status` | `""` (empty string) | `"CASCADE_RUN_STATUS_IDLE"` |
| `conversation_summaries.project_id` | `"default-cli-project"` | `"outside-of-project"` |
| Summary columns | 19 or 21 columns | 21 columns (includes `raw_summary`, `group_id`) |
| Subagent trajectory roots | root ID == conversation ID | root ID points to root cascade ID |

The main `trajectory_meta` row stores a fresh trajectory UUID, conversation UUID,
trajectory type `4` (cascade), and source `1` (`IDE`/`Hub`). `steps.idx` is a
contiguous zero-based sequence. Every step duplicates its type and status in
both the SQLite row columns and the serialized `Step` blob.

### Sidebar discovery and project grouping

Antigravity Desktop filters sidebar conversations strictly by active projects:

1. **Active Projects List**: Tracked in `app_storage.json` under `projectsOrder`.
- macOS: `~/Library/Application Support/Antigravity/app_storage.json`
- Linux: `$XDG_CONFIG_HOME/Antigravity/app_storage.json` (or `~/.config/Antigravity`)
- Windows: `%APPDATA%\Antigravity\app_storage.json`
2. **Project Configurations**: Stored in `~/.gemini/config/projects/<id>.json`,
defining `project_id`, workspace paths, and display labels.
3. Unassociated conversations (`project_id = "outside-of-project"`) are not
grouped in the project tree; assigning a registered project ID ensures instant
sidebar visibility.

## Protobuf subset and Hub cache

The adapter contains a bounded wire codec without generated vendor classes. It
accepts canonical varints, length-delimited bytes, and fixed 32/64-bit wire types.

The `Step` envelope uses:

| Field | Meaning |
| --- | --- |
| `1` | step type enum |
| `4` | step status enum |
| `19` | user-input payload when type is `14` (`CORTEX_STEP_TYPE_USER_INPUT`) |
| `20` | planner-response payload when type is `15` (`CORTEX_STEP_TYPE_PLANNER_RESPONSE`) |
| `140` | generic-tool payload when type is `132` (`CORTEX_STEP_TYPE_GENERIC_TOOL`) |

Status `3` is done, status `5` is cleared, and status `7` is error. User-input
field `2` stores visible user text. Planner-response field `1` stores visible
assistant text, field `6` stores a fresh message ID, and repeated field `7`
stores tool calls.

### Hub summary cache (`agyhub_summaries_proto.pb`)

Antigravity Desktop caches summaries in `agyhub_summaries_proto.pb`. On startup,
the native Go process reconciles SQLite records with this protobuf cache. If a
conversation exists in SQLite but has no entry in the cache or `raw_summary`
column, metadata fields reset to zero defaults (`0001-01-01`). The adapter
synchronizes both stores during installation.

## Conversion policy

| Portable event | Antigravity Desktop representation |
| --- | --- |
| User text | done user-input step |
| Assistant text | done planner-response step |
| Tool call | planner-response tool call |
| Tool result | following generic-tool step |
| Thinking/reasoning | omitted and counted as `thinking:private` |
| Compaction | omitted and counted |
| System/developer message | omitted as privileged context |
| Images and other context | omitted by type and counted |
| Unknown/opaque source event | omitted by reason and counted |

Private chain-of-thought is not portable. Thinking bytes and model signatures are
omitted from generated outputs, and source reading emits only a content-free
`thinking` marker.

A tool result without a preceding call receives a fresh synthetic call and an
explicit orphan counter. Duplicate or out-of-order IDs are rewritten or counted
to prevent corrupted native trajectories.

## Reading and installation

Source databases may have active write-ahead logs (`.db-wal`). The reader uses
SQLite's backup API to obtain a transactionally consistent snapshot, then hashes
and parses that snapshot. It validates:

- exact table, column, and schema invariants;
- SQLite page bounds and `integrity_check`;
- valid canonical UUIDv4 IDs and source `1` / `17` discrimination;
- contiguous step indices and supported step types; and
- structurally valid, bounded protobuf values.

Native installation creates target directories privately, reserves the summary
ID with `BEGIN IMMEDIATE`, writes the database atomically, and commits the
summary transaction. If a transaction fails, only newly created files are
unlinked. Existing sessions are never overwritten.

## Native validation evidence

1. **Synthetic Round-Trip Invariants**: Synthetic multi-turn sessions with tool
invocations, results, and thinking events serialize and re-parse with exact
fidelity, asserting that thinking text is removed.
2. **Native Language Server Verification**: The official Go binary
(`language_server`) was executed in an isolated sandbox, queried over Connect-RPC
(`GetCascadeTrajectorySteps`), and asserted to return all imported steps with
identical structure.
3. **Live User Session Migration**: A live ESPHome voice satellite conversation
with 256 steps was migrated from Antigravity CLI to Antigravity Desktop,
confirming complete rendering and sidebar searchability.

Run the test suite with:

```console
uv run pytest -q tests/test_antigravity_desktop_format.py
```

Run the native language server oracle (macOS with Antigravity Desktop installed):

```console
uv run pytest -q tests/test_antigravity_desktop_native.py
```

## Known boundaries

- Native oracle hash validation is pinned to official release builds. Unvalidated
binaries can be tested with `SESSION_MIGRATE_UNVALIDATED_DESKTOP_BIN=1`.
- Generic tool transport is visually render-proven; internal vendor-privileged tools
are preserved as generic tool steps to maintain auditability.
- Private reasoning tokens, system instructions, and ephemeral UI selections are
not transferred.
- Subagent conversations are mapped to independent portable sessions with their
parent reference preserved in metadata.
4 changes: 2 additions & 2 deletions docs/cli-reference.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# CLI reference

This page documents `session-migrate` 0.11.0. `smigrate` is an exact shorthand
This page documents `session-migrate` 0.12.1. `smigrate` is an exact shorthand
for the same executable.

## Commands
Expand Down Expand Up @@ -175,7 +175,7 @@ installation still requires the exact pinned version.
| Grok | `$GROK_HOME`, otherwise `~/.grok` |
| Kilo Code | official CLI under its normal XDG data root |
| OpenHands | `$OPENHANDS_CONVERSATIONS_DIR`, otherwise `~/.openhands/conversations` |
| Hermes Agent | `$HERMES_HOME`, otherwise `~/.hermes` |
| Hermes Agent | `$HERMES_HOME`, otherwise the CLI's platform default: `%LOCALAPPDATA%\hermes` on Windows, `~/.hermes` elsewhere |
| MastraCode | `$MASTRA_DB_PATH`; otherwise `$MASTRA_APP_DATA_DIR/mastra.db` or the platform data directory |
| Devin CLI | `$XDG_DATA_HOME/devin/cli`, otherwise `~/.local/share/devin/cli` on Linux |

Expand Down
10 changes: 9 additions & 1 deletion docs/credential-free-native-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ No production credential is read, translated, or written by this workflow.
| Cursor `2026.03.20-44cb435` | Shipped backend loads blobs and the real TUI renders imported text; no offline model append |
| Devin 3000.6.7 | Native list/resume selection and ACP `session/load`; stops at vendor authentication |
| Grok 1.0.5 | OpenAI-compatible override; native creation, reload, TUI replay, and append |
| Hermes 0.20.6 | OpenAI-compatible override; replay, append, and compaction |
| Hermes 0.22.2 | OpenAI-compatible override; replay, append, and compaction |
| Kilo 7.5.0 | Official import/export plus OpenAI-compatible replay and append |
| Kimi 0.38.0 | OpenAI-compatible override; imported history replays and the reply persists |
| MastraCode 0.37.1 | OpenAI-compatible override; replay and append |
Expand Down Expand Up @@ -82,3 +82,11 @@ harness and installations do not compete for disk space.
The normal Python job separately runs the deterministic 18 by 18 route oracle.
The native matrix is the independent acceptance layer: generated files must be
accepted by code owned and shipped by each harness.

## OpenCode v2 variant

The additional `opencode-v2` job pins `@opencode/cli@2.0.23` and sets
`SESSION_MIGRATE_TEST_OPENCODE_V2`. Its runner requires every assigned test to
run without skips, exercising synthetic import/export, collisions, cold reopen
and localhost-only continuation. Legacy `opencode` remains pinned to 1.17.20.
See [the v2 transfer contract](opencode-v2.md).
2 changes: 1 addition & 1 deletion docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pytest and Ruff are development dependencies locked by `uv.lock`.
| `src/session_migrate/formats/grok.py` | Grok 1.0.5 ACP-update adapter |
| `src/session_migrate/formats/kilo.py` | Kilo Code 7.5.0 official-bundle adapter |
| `src/session_migrate/formats/openhands.py` | OpenHands 1.16.0 SDK-event adapter |
| `src/session_migrate/formats/hermes.py` | Hermes Agent 0.20.6 shared-state adapter |
| `src/session_migrate/formats/hermes.py` | Hermes Agent 0.22.2 shared-state adapter |
| `src/session_migrate/formats/mastracode.py` | MastraCode 0.37.1 LibSQL adapter |
| `src/session_migrate/formats/devin.py` | Devin CLI 3000.6.7 active-forest adapter |
| `src/session_migrate/formats/common.py` | Shared timestamps, text, and image validation |
Expand Down
13 changes: 11 additions & 2 deletions docs/format-compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ to separately installed host binaries:
| Codex CLI | `0.144.4` |
| Pi source and target | `0.80.6` |
| Oh My Pi source and target | `18.0.5` |
| OpenCode source and target | `1.17.20` |
| OpenCode legacy source and target | `1.17.20` |
| OpenCode v2 transfer adapter | Linux gateway build `2.0.23` |
| GitHub Copilot CLI source and target | `1.0.70` |
| Antigravity CLI source and target | `1.1.16` |
| Antigravity Desktop source and target | `2.18.1` |
| Cursor Agent experimental text adapter | `2026.03.20-44cb435` |
| Mistral Vibe source and target | `2.24.3` |
| Muse Code source and target | `0.2.1 (0.2.1-R1215.1)` |
Expand All @@ -31,7 +33,7 @@ to separately installed host binaries:
| Grok source and target | `1.0.5` |
| Kilo Code source and target | `7.5.0` |
| OpenHands source and target | `1.16.0` (SDK `1.21.0`) |
| Hermes Agent source and target | `0.20.6` (tag `v2026.8.27`) |
| Hermes Agent source and target | `0.22.2` (tag `v2026.9.24`, SQLite schema `31`) |
| MastraCode source and target | `0.37.1` |
| Devin CLI source and target | `3000.6.7` (`260a97c8`) |

Expand All @@ -54,6 +56,13 @@ rendering without a model append; Devin proves ACP loading and the vendor-login
boundary. See
[Credential-free native client testing](credential-free-native-testing.md).

OpenCode 2.0.x has a separate public-transfer adapter. Its local synthetic tests
cover native import/export, tool linkage, completed compaction, dry-run and
identity conflicts; this does not extend the historical eighteen-client corpus
validation claim. See [OpenCode v2 transfers](opencode-v2.md) for exact scope and
limitations. No real user transcript migration or native Windows validation has
been performed for this adapter.

All eighteen formats are sources and targets. Their mappings, native probes, and
loss keys are specified in [Additional native formats](additional-target-formats.md),
[OpenCode source research](opencode-source-exploration.md),
Expand Down
Loading
Loading