dsh-codex-handoff: Hand off Codex CLI multi-turn sessions to DeepSeek Harness

Introduction

When developing in DSH (DeepSeek Harness), a common situation arises: both sides have command-line assistants. DSH runs DeepSeek, and Codex CLI is installed locally, but their sessions do not communicate—sending a task from here results in a response from there that disconnects immediately, and the next round requires pasting the context again. Model selection and workload intensity cannot be controlled either.

hato-24/dsh-codex-handoff (gpt_bridge) is a client plugin written to solve this problem: it connects the local Codex CLI’s multi-turn sessions into DSH. The history is checkable in the sidebar. After sessions are stored in the database, they can be resumed. Models and reasoning intensity can also be switched. Below is an introduction to its positioning, installation method, and actual usage.

What is this

One-sentence definition: Multi-turn dialogue bridge for Codex CLI. After installing the plugin, a GPT dialogue panel appears in DSH. At the same time, it registers a codex_gpt tool for the agent, allowing GPT to be called as a sub-agent. Sessions are persisted by default and can be resumed using codex exec resume to continue the same thread.

  • Maintainer: HATO-24
  • Category: Client (contains both Host side and Client side components)
  • License: MIT

It solves three things: 1. Visibility of interactions; each Q&A round can be viewed by clicking in the DSH sidebar. 2. Resumability; sessions are written into the Codex session library, so chatting continues even if the command changes. 3. Configurable levels; model and reasoning intensity are switched via the interface rather than hardcoded in scripts.

Core Functions

The plugin consists of three parts:

Component Function
Host side lib/index.js Calls codex exec, maintains .bridge storage, provides /api/codex-bridge/* routes, registers codex_gpt tool
Client side lib/client.js Sidebar “GPT Chat” entry + Main panel (session list, per-round questions/replies)
gpt_bridge.ps1 (Upgrade version) Command-line bridge, persists sessions by default, records thread_id, supports -Resume

Data lands in <workspace>/.bridge/ in the workspace, sharing the same directory set as gpt_bridge.ps1, so old records before the upgrade are also visible.

Installation & Enablement

Prerequisites: DSH is installed locally, and Codex CLI is logged in and callable. The plugin will automatically look for the codex executable in %LOCALAPPDATA%\OpenAI\Codex\bin\*\codex.exe, CODEX_BIN, or PATH.

dsh-codex-handoff@0.1.1

Two installation methods, choose one:

  1. Interface operation: Plugins page → Add → Enter dsh-codex-handoff
  2. Tool installation: plugin_manager → install_bundle, fill target with dsh-codex-handoff@0.1.1

Note: The version number here is filled according to the original README installation section; the version declared in the repository’s package.json is 0.1.3.

After installation, three entry points will appear on the interface:

  • Bottom left (next to Settings, next to the update notification bot) adds a new GPT button, clicking it opens the dialogue panel in the DSH sidebar.
  • GPT Chat tag appears at the top of the sidebar (alongside “Start”).
  • The dialogue bubble button at the far right of the session title bar, serving as a shortcut.

Two points to note:

  • After the Client plugin changes inject, restart DSH for new configurations to be parsed.
  • After changing code locally, simply disable → enable the plugin in the plugin page to reload it; no need to restart DSH.

Also, the icon in the left sidebar cannot be used as an entry point: it switches the current conversation, causing sidebarRight.mounted to become empty and openResource to throw sidebarRight: no session surface is mounted, which is a mechanism limitation of DSH.

Viewing Records & Sending Messages in Sidebar

Click the GPT button in the bottom left (or the bubble button at the head of the session), and the sidebar expands the “GPT Chat” tab. The sidebar can be resized by dragging the divider bar; the main panel is unaffected, and the dialogue proceeds normally.

The bottom of the panel is the send area:

  • Input box sends with Enter, new line with Shift+Enter;
  • Model dropdown comes from all 10 models listed by codex debug models (GPT-6.1-Sol, GPT-6-Astra, GPT-6.1 Terra, GPT-6-Sol, etc.);
  • Reasoning dropdown follows the levels supported by the selected model (low/medium/high/xhigh/max/ultra);
  • When a specific session segment is selected, the two dropdowns auto-fill with the model and reasoning intensity used for that session last time; sending directly continues using them; switching sessions resets them.

It records “what was actually used”: after each round ends, the plugin reads the real model and effort from turn_context in the rollout and writes them into actualModel/actualEffort in inbox/<id>.json. It does not display null values when the model is not passed. The actual comparison in the README is as follows (request parameters model=gpt-6.1-sol, reasoning=high):

Source model effort
Request Params gpt-6.1-sol high
Bridge Record actualModel gpt-6.1-sol high
Rollout turn_context gpt-6.1-sol high

Therefore, cards and session headers can distinguish gpt-6.1-sol from gpt-6-sol. These are different models; the former defaults reasoning to low, the latter to medium.

Session identification rules: Sending while a specific session segment is selected equals continuing that Codex session; sending without selection opens a new segment. After sending, it automatically selects the new session and refreshes the list.

Let GPT Act as a Sub-agent: codex_gpt & Multi-turn Continuation

The DSH agent sees the new tool codex_gpt, with parameters message (required), conversationId/threadId (one of the two), model, reasoning:

codex_gpt({ message: "Review milestones in docs/plan.md, find unexecutable parts", reasoning: "high" })
→ { conversationId: "c-...", threadId: "01a1...", reply: "..." }

For the second round, pass the same conversationId to continue the same Codex session without resending context:

codex_gpt({ conversationId: "c-...", message: "Expand on point 2, give specific changes" })

You can also directly resume any Codex thread:

codex_gpt({ threadId: "01a1ac8e-01a4-79a2-a70d-855254e70751", message: "Continue with the previous plan" })

Two pitfalls worth mentioning upfront:

  1. Reasoning levels are uniformly low / medium / high / xhigh / max / ultra; there is no minimal nor none. Passing minimal, which old scripts are used to, will directly cause turn.failed.
  2. If model/reasoning are not passed, Codex defaults are used; if passed, they use -m and -c model_reasoning_effort=…. The README confirms they take effect.

HTTP Interface

Route prefix /api/codex-bridge, default port http://127.0.0.1:12530:

Method Path Function
GET /list Session list (including old records) + current default configuration
GET /read?id=<id> Per-round questions and replies of a session + Codex side original text
GET /status Workspace, codex path, isolation switch
GET /models Available models directory (slug / display name / supported reasoning levels)
POST /send Send a round of real dialogue, body: {message, conversationId?, threadId?, model?, reasoning?}
POST /promote Mark a session as visible to Codex App, body: {threadId} or {conversationId}

Send a round:

$body = @{ message = "Reply with only two words: Received"; reasoning = "low" } | ConvertTo-Json -Compress
Invoke-WebRequest -Uri "http://127.0.0.1:12530/api/codex-bridge/send" -Method POST `
  -Body $body -ContentType "application/json" -UseBasicParsing -TimeoutSec 900
# → {"conversationId":"c-...","threadId":"01a1...","reply":"Received"}

Two points to note: POST /send will actually consume Codex quota, and it waits synchronously. The README tested it takes about 58 seconds for one low reasoning. Also, the route uses Node’s native handler instead of resource, because resource routes only allow GET/HEAD, and POST would be directly 405ed by the platform layer.

Context & Isolation: What GPT Can See

This is the initial question this plugin answers. The README tested using zero quota: codex debug prompt-input "test" prints exactly what the model receives as a JSON array. Looking at them one by one, what the model sees far exceeds the segment of prompt sent through the bridge.

Injected Item Test Evidence Size/Content
Global Persona Instructions developer message line 1 prompts/gpt-with-taste/main.md pointed to by model_instructions_file in ~/.codex/config.toml, 24,461 characters
Skills List developer message line 2 <skills_instructions> 4,897 characters, listing skill roots like ~/.codex/skills/.system, plugins/cache/openai-bundled, etc. GPT can read SKILL.md itself once it sees the paths
MCP Tools Tool table mcp__cua_repl.js etc., from [mcp_servers.node_repl] in config.toml
Plugin Recommendation List developer message <recommended_plugins> 876 characters, 16 “available but not installed” plugins
Multi-agent System Prompts developer message <multi_agent_role> / <multi_agent_mode> 2,400 + 271 characters
Environment Context user message <environment_context> cwd, shell, date, timezone, file system permission roots
Codex Memory [features] memories = true / [memories] use_memories = true in config.toml Will read memories_1.sqlite / memories_v2_1.sqlite

Conclusion: The bridge is only responsible for sending one segment of prompt; everything else is loaded by Codex itself. To get a cleaner context, you can turn on the plugin’s isolation switch DSH_CODEX_BRIDGE_ISOLATE=1 (or command line -Isolate), default is off. More thorough isolation methods are Codex CLI’s own parameters; the README provides three levels:

# 1) Complete isolation: do not load ~/.codex/config.toml (auth still uses CODEX_HOME)
codex exec --ignore-user-config -m gpt-6-sol ...

# 2) Only disable plugin recommendations
codex exec --disable plugins ...

# 3) Only disable MCP
codex exec -c 'mcp_servers={}' ...

Note that --ignore-user-config will also lose configuration like model, so -m must be explicitly passed when isolating.

Use Cases & Notes

Suitable for these types of usage: want GPT to participate in multi-turn collaboration in DSH as a sub-agent; want Codex sessions to continue in the Codex desktop app or CLI instead of dissipating after use; need to switch models and reasoning intensity based on tasks and archive them.

A few things need to be confirmed before getting started:

  • The plugin runs with the permissions of the current DSH process and can read Codex CLI’s environment and configuration. Unverified source code is suggested to be reviewed personally before installation; the license is MIT.
  • Sessions will consume Codex account quota. It is recommended to first use codex debug prompt-input and the isolation switch to confirm the scope of context, then decide whether to target specific questions.
  • Old records come from outbox/*.prompt.md, inbox/<id>.json, and logs/<id>.stdout.jsonl. Thread IDs can be retrieved from these two places. The README tested listing 3 old records before the upgrade, of which 2 successfully recovered thread IDs, and the other 1 is an empty record where the template didn’t write a reply.

Conclusion

This plugin turns the “use and discard” Codex CLI dialogue into a link in the DSH workflow that is checkable, resumable, and has switchable levels. The changes focus on the sidebar panel, the codex_gpt tool, and the HTTP routes. The scope of change is small but the anchor points are clear.

Community Plugin Directory Page: https://www.skillhub.cn/plugins/HATO-24/dsh-codex-handoff ; Source Code: https://github.com/HATO-24/dsh-codex-handoff . This directory is an independent site and has no official affiliation with DeepSeek / Huanfang.

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye