dsh-claude
Run the local Claude Code CLI as a first-class main conversation inside DeepSeek Harness (DSH).
dsh-claude does not recreate Claude Code with an API client. It starts the user's installed claude executable through the official Agent SDK protocol, keeps one live process per active DSH session, and leaves Claude Code in charge of its own agent loop, tools, CLAUDE.md, Skills, Hooks, Plugins, MCP servers, settings, and authentication.
What it adds
- A
ClaudeAgent Preset in the normal new-session preset picker. - A
claudeDSH model provider with Claude Code'sdefault,opus[1m],fable,sonnet, andhaikuchoices. - Long-lived Claude processes with per-session serialization, idle eviction, cancellation, and persisted Claude session resume.
- DSH approval prompts for Claude tool permission requests.
- Durable, redacted plugin-sidecar activity for thinking summaries, tool calls/results, permissions, subagents, status, usage, and errors.
- Native turn-tail activity cards and a Settings → Claude Code Doctor panel.
- A safe CLI for Doctor and managed preset install/remove.
Requirements
- macOS (v0.1 verification target).
- DeepSeek Harness compatible with
0.1.0-rc.5public plugin APIs. - A local Claude Code installation already authenticated by the user.
- Node.js 20 or later.
The plugin never manages Claude credentials. Use an already authenticated local Claude Code installation, or configure its absolute executable path in DSH.
Install in DSH
Install the published package into the DSH Web profile:
dsh plugin --profile web add @norman-else/dsh-claude
Wait for the Web profile to rebuild, then refresh the existing DSH page. Open a new conversation and select Claude from the Agent Preset picker.
The Host plugin automatically installs a two-file managed preset at:
$DSH_HOME/.agent-presets/claude/
It writes only absent files. If that preset id already contains different content, activation fails rather than overwriting user work.
Use
- Open a new DSH conversation.
- Choose Claude in the Agent Preset picker.
- Choose Default (recommended), Opus (1M context), Fable, Sonnet, or Haiku.
- Send a normal text prompt.
- Answer Claude tool permissions through the existing DSH approval UI.
- Expand Claude Code activity beneath a completed assistant turn to inspect the redacted execution trail.
Native DSH presets remain available and keep the native DSH agent loop.
Current input boundary
v0.1 forwards only the newest direct human text in a DSH step. It intentionally ignores the DSH system prompt, DSH tool schemas, and injected plugin messages because Claude Code owns those surfaces. Image-only prompts are rejected with an actionable error.
Permission and sandbox boundary
Claude Code runs in its normal local configuration and can read/write ~/.claude so that authentication, settings, plugins, and session recovery continue to work.
Every Claude permission callback is bridged to ctx.approval.request(...):
allowed-onceis the only granting result.- reject, cancel, missing answerer, and audit failure all deny the action.
- DSH
neverapproval policy therefore fails closed. - DSH access modes map to Claude permission modes:
read-only→plan,workspace-write→acceptEdits, and explicitly acknowledgeddanger-full-access→bypassPermissions.
This is a permission-policy bridge, not kernel-level workspace confinement. DSH 0.1.0-rc.5 exposes one writable sandbox root, while full Claude compatibility also requires writable ~/.claude. The plugin therefore does not claim that paths outside the workspace are technically unwritable. It still uses DSH managed subprocess ownership for explicit argv, credential-shaped environment scrubbing, cancellation, and whole-process-tree termination.
Process and recovery behavior
- One live streaming-input Claude query per active DSH session.
- One active top-level turn at a time per session.
- Default maximum: 4 live Claude processes.
- Default idle eviction: 30 minutes.
- The Claude session id and redacted presentation metadata are persisted in a plugin-owned sidecar under
$DSH_HOME/plugins/dsh-claude/sessions; new DSH logs contain noclaude-code/*events. - After normal eviction or DSH restart, the next prompt resumes that Claude session.
- A crash after visible Claude/tool activity is reported as outcome unknown. The plugin never automatically replays that prompt because its side effects may already have happened.
- Cancelling a DSH turn interrupts Claude and tears down that session's process entry (bounded interrupt, then close/abort/terminate/join); the next prompt re-establishes the process from the persisted Claude session id. Plugin unload and agent disposal also terminate the owned process tree.
- DSH outer model retries are disabled for this provider.
Doctor
Inside DSH, open Settings → Claude Code and run Doctor.
From the checkout:
node lib/bin.mjs doctor
node lib/bin.mjs doctor --executable /absolute/path/to/claude
Doctor reports only the resolved executable, version, coarse authentication category/method/provider/subscription, handshake state, configured limits, and process count. It never returns tokens, email, organization id, settings content, or environment secrets.
Executable resolution order:
- configured absolute path
claudeon DSH's scrubbed PATH~/.local/bin/claude/opt/homebrew/bin/claude/usr/local/bin/claude
To configure a nonstandard path, edit the plugin row in the Web profile composition:
- id: llm-claude
name: @norman-else/dsh-claude
config:
executablePath: /absolute/path/to/claude
model: default
idleTimeoutMs: 1800000
maxProcesses: 4
Development
git clone https://github.com/Norman-else/dsh-claude.git
cd dsh-claude
export PATH="/opt/homebrew/bin:$PATH"
pnpm install
pnpm check
To test this source checkout in DSH without publishing it:
dsh plugin --profile web add "link:$(pwd)"
To inspect the package that would be published:
pnpm pack --pack-destination ./dist-pack
Release
Update the version in package.json, commit it, and push the clean release commit first. Then verify and publish both npm and GitHub releases:
pnpm release:check
pnpm release
The release script requires HEAD to match the current branch on origin. It runs the full project check and npm package preview, publishes the public npm package, verifies npm's gitHead, and creates a matching v<version> GitHub Release with generated notes. It is safe to rerun after a partial failure: an existing npm version or GitHub Release is accepted only when it points to the current commit.
The project uses fixture/state-machine tests and a minimal SDK-level handshake probe (a tool-disabled, one-turn query() against the resolved local executable). Full DSH-linked live acceptance (native coexistence, Claude turn, permission allow/deny, cancel, resume, orphan-process check) is run after the Host restart per INSTALL.md. The Agent SDK is pinned to 0.3.233; runtime execution is forced to the resolved local Claude executable through pathToClaudeCodeExecutable.
Uninstall
Remove the managed preset while this package is still present:
node lib/bin.mjs remove-preset
Then remove the package from the Web profile:
dsh plugin --profile web remove @norman-else/dsh-claude
The preset remover deletes only files whose contents exactly match the package-managed copies. It refuses to delete modified content.
Troubleshooting
Claude preset appears broken
Run node lib/bin.mjs install-preset. If it reports a conflict, move or rename the existing $DSH_HOME/.agent-presets/claude directory; the plugin will not overwrite it.
Executable is missing
Run Doctor and set an absolute executablePath. GUI application PATH often omits ~/.local/bin.
Claude is signed out
Run the supported local flow directly:
/absolute/path/to/claude auth login
DSH does not proxy login or store credentials.
A turn says “outcome unknown”
Inspect the activity record and workspace before sending a new instruction. Do not repeat a potentially side-effecting prompt blindly.
Architecture records
- Product and architecture spec:
docs/aegis/spec/2026-08-15-dsh-claude-spec.md - Implementation plan:
docs/aegis/plan/2026-08-15-dsh-claude-implementation-plan.md
No comments yet. Be the first to write one.