Skip to content

fix(opencode): read and write OpenCode 2.1 sessions - #97

Open
acaprino wants to merge 7 commits into
skillsynchq:mainfrom
acaprino:fix/opencode-2.1
Open

acaprino wants to merge 7 commits into
skillsynchq:mainfrom
acaprino:fix/opencode-2.1

Conversation

@acaprino

@acaprino acaprino commented Oct 27, 2026 •

Copy link
Copy Markdown

Issue: #96

What changed and why?

OpenCode 2.1 moved sessions to new tables, flattened the transcript, and renamed the import command, so the opencode harness read nothing and wrote nothing against 2.1.4 (details and logs in #96). This PR makes it work on 2.1 and keeps 2.0 working.

Before: txcript list --from opencode → no local opencode sessions found on a database with 101 sessions. txcript continue run.json --with opencode → `opencode import` failed: Unexpected positional argument, and the staged file is rejected by opencode session import (Missing key at ["info"]["projectID"], then Expected Session.Message.Info at ["messages"][0]).

After: txcript list --from opencode lists the sessions; txcript continue run.json --with opencode prints Imported session: ses_… and the session opens in OpenCode 2.1.4. A 2.0 database still reads, and a 2.0 CLI still gets the old export through opencode import.

How:

  • Store. OpenCodeStore detects the layout from sqlite_master (session_v2 present → 2.1) and reads session_v2 + session_message (one flat record per message, in seq order) or the old session/message/part tables. fingerprints and delete follow the same switch.
  • Save. save runs opencode --version once: 2.1 and later get the flat document through opencode session import <file> --directory <cwd> (the transcript's cwd when it exists on this machine); earlier releases keep opencode import and the {info, parts} export.
  • Codec. The native body stays the 2.0 export, which the codec already understands; a new src/harness/opencode/v2.rs projects it to and from the 2.1 document (header with projectID, cost, tokens, location, model; user/synthetic/assistant records; tool calls with state.content, state.error {type, message}, tool-calls finish). Records 2.1 has that 2.0 cannot express (compaction, idle, shell, system, *-switched) ride along verbatim and are skipped by the codec. The text form (to_text, so the WASM convert/fromCommon output) is now the 2.1 document; from_text reads both layouts. Built-in tools carry their 2.1 names and input keys: bash is shell (timeout, background), task is subagent (agent), skill takes id, websearch is lowercase, read/edit/write take path, and grep takes include, limit and caseSensitive; reading maps them back, and every other key is kept.

Tests: one per behaviour — discover_and_load_from_a_2_1_database (store on a 2.1 SQLite fixture: discovery, load, records 2.0 cannot express kept, fingerprints), to_text_writes_the_2_1_document_and_reads_it_back (the 2.1 header, flat records and 2.1 tool names/keys, read back to the same conversation), and cli_generation_is_read_from_the_version_line (session import for 2.1+, import before). docs/formats/opencode.md and the changelog are updated.

Verified live on Windows against OpenCode 2.1.4 (opencode --version): discover lists the 37 active sessions of a real 2.1 database (written by 2.1.1 and 2.1.4) and loads the newest one (18 records → 103 Common messages), and a conversation written through txcript::local::write (the path continue --with opencode takes) is imported by opencode session import, discovered, loaded from session_message and read back as the same four messages. The CLI crate could not be built on this machine (its default features pull BoringSSL, which needs cmake/nasm), so the library checks ran with --no-default-features --features opencode,hermes,search,codex_zstd plus the codec-only and wasm32 CI steps.

Unrelated, seen while running the codec-only tests: store_delete::antigravity_delete_roundtrip is not gated on the opencode feature (its siblings are), so cargo test -p txcript --no-default-features fails on main too. Left alone here.

One known loss, noted in the format doc: the 2.1 header has no CLI version field, so Meta.cli_version survives a database load but not a text round-trip.

…sage

A source can record parallel tool calls one call per assistant message, each
result in its own later user message (call A, call B, result A, result B).
The writer looked for a result only in the message right after its call, so
both calls were written with an empty output. It now looks through the
following user messages, up to the next prompt.

Fixes skillsynchq#98
OpenCode 2.1 keeps sessions in `session_v2` and one flat `session_message`
record per message, exports `{info, messages: [record]}`, and imports with
`opencode session import`. The harness still queried the 2.0 tables, wrote
the `{info, parts}` export and ran `opencode import`, so against 2.1.4 it
found no sessions and every `continue --with opencode` failed.

The store now picks the table layout from `sqlite_master`, `save` picks the
command and document from `opencode --version`, and a new `v2` module
projects the native 2.0 body to and from the 2.1 document, which is also the
text form. 2.0 databases and CLIs keep working.

Closes skillsynchq#96
OpenCode 2.1 renamed several built-in tools and input keys: `bash` is
`shell` (`timeout`, `background`), `task` is `subagent` (`agent`), `skill`
takes `id`, `websearch` is lowercase, `read`/`edit`/`write` take `path`, and
`grep` takes `include`, `limit` and `caseSensitive`. The 2.1 document now
uses those names and keys, and reading it maps them back, so every other key
survives a round trip unchanged.

Refs skillsynchq#96
After a compaction Claude Code keeps the earlier rows in the file before the
`compact_boundary` and writes the summary as a user row flagged
`isCompactSummary`. Reading in file order already carries that history, so
the summary became a user turn that repeated it. It now stays in the native
body only.

Fixes skillsynchq#100
One test each for reading a 2.1 database, writing the 2.1 document and
reading it back, and choosing the import command from the CLI version. The
others repeated these or pinned single details.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant