Preface¶
If you use Codex, Claude Code, Pi, Reasonix, OpenCode, and DSH simultaneously, you will encounter a specific problem: conversation logs are scattered in the storage of each tool, and the formats are incompatible with each other. To continue a previous conversation in DSH, or hand over a DSH session to another tool, it is basically only possible to organize it manually.
The dsh-shuttle introduced below solves this problem. It is a DeepSeek Harness plugin that also provides an offline CLI for bidirectional migration of conversation logs between DSH and these five types of tools. DSH’s philosophy is “everything is a plugin”; capabilities like conversation migration are also integrated in the form of plugins rather than modifying the DSH core itself.
What is this¶
The dsh-shuttle repository is omdsh-dev/dsh-shuttle, package name @deepseek-ai/dsh-shuttle, maintained by omdsh-dev, licensed under MIT, current version 0.1.0. It supports bidirectional migration of conversation logs between DSH and Codex, Claude Code, Pi, Reasonix, and OpenCode. It can be used as a plugin inside DSH or run offline as a standalone CLI.
How Migration Works¶
Before migration, each source is first projected into a provider-neutral intermediate model, then converted into a DSH event or the target platform’s native import format. Where supported by the target, text, reasoning content, tool calls and results, timestamps, working directory, and provider/model identity are all preserved.
Not all data is portable: Provider-private replay state, cached data, UI-only events, token chunks, and database indexes are outside the scope of migration. Binary/image attachments that cannot be safely copied as bytes are converted into text placeholders.
Security Design¶
There are several hard constraints for write operations:
- Default is dry-run; writing is only actually performed with
--apply; - Existing DSH IDs and target files are skipped and never overwritten;
- Reading has size/quantity limits and does not recursively traverse symbolic link directories;
- DSH writes use
ctx.sessionPersistence; both JSONL and SQLite backends work; - OpenCode is handled via official export/import JSON envelopes and never directly edits its database;
- The shuttle never deletes source history.
Installation and Enabling¶
The README does not provide specific installation commands, only stating that the package is installed via the standard DSH plugin workflow. After installation, the bundled cordis.patch.yml mounts the ctx.shuttle and migrate-conversations skills, and the plugin exports standard name, inject, Config, and apply symbols.
The runtime environment is Node ^22.19.0 || >=24.0.0, package manager pnpm@11.7.0. Before using the CLI, you need to build first:
pnpm install
pnpm build
After building, the CLI entry point is lib/cli.js, and the registered bin command name in package.json is dsh-shuttle.
Migration via Settings UI¶
Open Settings → Conversation migration to see two independent import/export units; manual command assembly is not required:
- In Import to DSH, select the source platform; optionally set source path and quantity limit;
- In Export from DSH, select the target platform, DSH task, target path, and scope;
- Preview each unit separately. Settings preview uses a dedicated Remote API; it does not create DSH sessions or write to target files;
- View the report for that unit, check the confirmation box, and then execute the import or export.
The execute button is only available after the current form is successfully previewed; changing any migration input will invalidate the preview.
Slash Command /shuttle¶
In an environment with an interactive DSH command service, you can type /shuttle in the session input to view help and execute import/export; the results are displayed directly in the UI and not sent to the model:
/shuttle import codex
/shuttle import codex --source "~/.codex/sessions" --apply
/shuttle export pi --destination "~/.pi/agent/sessions"
/shuttle export opencode --session <id> --destination /tmp/opencode --apply
Without --apply, everything is a preview. Export defaults to the current UI session; selection can be changed by repeating --session or using --all.
CLI Usage¶
The CLI provides import/export subcommands, supporting --from/--to, --source, --destination, --session (repeatable), --all, --apply, and --dsh-root. The workflow is build, then preview, then add --apply to write after confirming the report.
First look at import. Default DSH storage is $DSH_HOME/sessions or ~/.dsh/sessions, which can be overridden with --dsh-root:
node lib/cli.js import --from codex
node lib/cli.js import --from claude-code --source ~/.claude/projects
node lib/cli.js import --from pi --source ~/.pi/agent/sessions
node lib/cli.js import --from reasonix --source ~/.reasonix
After checking the JSON report, add --apply to repeat the same command to complete the write.
Export direction:
node lib/cli.js export --to codex --session <id> --destination ~/.codex/sessions --apply
node lib/cli.js export --to pi --destination ~/.pi/agent/sessions --apply
node lib/cli.js export --to reasonix --destination ~/.reasonix --apply
Repeating --session allows selecting multiple sessions; omitting it exports up to the configured maxSessions limit.
OpenCode read/write is coordinated with its own export/import commands:
opencode export <session-id> > /tmp/opencode-session.json
node lib/cli.js import --from opencode --source /tmp/opencode-session.json --apply
node lib/cli.js export --to opencode --session <dsh-session-id> \
--destination /tmp/dsh-opencode --apply
opencode import /tmp/dsh-opencode/<dsh-session-id>.opencode.json
For Reasonix, if new authoritative JSONL sessions are not displayed in its directory after writing, run reasonix sessions reindex once.
Plugin API and Configuration¶
The plugin exposes two APIs, following the same preview-then-write pattern:
const preview = await ctx.shuttle.importConversations({
from: 'codex',
source: '/path/to/.codex/sessions',
})
await ctx.shuttle.importConversations({
from: 'codex',
source: '/path/to/.codex/sessions',
apply: true,
})
await ctx.shuttle.exportConversations({
to: 'claude-code',
sessionIds: ['session-id'],
destination: '/path/to/.claude/projects',
apply: true,
})
Two configuration items control read limits:
| Config Item | Default | Meaning |
|---|---|---|
maxFileBytes |
64 MiB | Maximum size of a single external artifact |
maxSessions |
500 | Maximum number of artifacts/sessions per operation |
Use Cases and Notes¶
It is suitable for developers who switch between multiple coding agents, want to consolidate historical sessions into DSH, or need to hand over DSH sessions to other tools for continued use. Pay attention to two points before using:
- Codex and Claude Code do not promise a stable public disk transcription schema. The reader is lenient, but after upgrades from these two, re-previewing is required; exported Codex/Claude JSONL matches the currently observed envelope, and future clients may require explicit importers or adapter updates.
- The plugin runs with the permissions of the current dsh process; check the source code and license (MIT) before installing.
Conclusion¶
Following the steps above, conversation logs scattered across various tools become portable data; the design of default preview and never-overwriting ensures every write is controllable. For code and documentation, see the GitHub repository: