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:

  1. In Import to DSH, select the source platform; optionally set source path and quantity limit;
  2. In Export from DSH, select the target platform, DSH task, target path, and scope;
  3. Preview each unit separately. Settings preview uses a dedicated Remote API; it does not create DSH sessions or write to target files;
  4. 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:

https://github.com/omdsh-dev/dsh-shuttle