5.7 KiB
DeepSeek Harness Guide
ECC runs on the DeepSeek Harness (DSH) via its native skill roots and the first-party Claude Code hooks bridge. This guide covers what works out of the box, how to mount the ECC hooks, and the current limits.
Unlike the Qwen or Codex adapters, there is no dedicated installer target yet; the setup is a small amount of manual configuration described below.
Prerequisites
- DeepSeek Harness 0.2.0-rc.1 (the verified version; reverify newer releases) (
dsh --version). - ECC repository cloned locally, for example
~/ECC(the hooks bridge commands reference this path, so keep the checkout in place). - Skills need no extra tooling; hooks use the
@deepseek-ai/dsh-hooks-claude-codeplugin that ships inside the DSH runtime itself.
Skills (automatic)
DSH loads skills from these roots (earlier roots win on name conflicts):
<project>/.dsh/skills
<project>/.agents/skills
custom dirs (~/.dsh/profiles/<profile>/cordis.patch.yml -> skill-filesystem)
~/.dsh/skills
~/.agents/skills
Because ECC already ships .agents/skills/ for Codex, opening a session with the
ECC checkout as the working directory exposes a subset of ECC skills immediately.
To expose the full curated set in every project, link the catalog once:
ln -s /path/to/ECC/skills/<skill-name> ~/.dsh/skills/<skill-name>
Run this per skill with real names substituted for both placeholders (for
example ln -s ~/ECC/skills/tdd-workflow ~/.dsh/skills/tdd-workflow); the
angle brackets are placeholders, not shell syntax.
DSH reads SKILL.md frontmatter (name/description), which matches the ECC skill
format, so no conversion is needed. Name conflicts with pre-existing user skills
are resolved by root priority; skip those skills when linking.
Hooks
How the bridge works
DSH bridges ECC command hooks through @deepseek-ai/dsh-hooks-claude-code
(first-party, bundled with the runtime). Constraints that shape the conversion:
- Supported events:
SessionStart,UserPromptSubmit,PreToolUse,PostToolUse,Stop,SubagentStart,SubagentStop. ECC events without a bridge counterpart (PreCompact,PostToolUseFailure,SessionEnd) are skipped by the generator. - DSH tool names are lower-case (
bash,edit,write,skill,task), while ECC matchers use Claude Code names (Bash,Edit|MultiEdit, ...). The generator maps known tool names and keeps regex passthrough tokens. - The bridge runs commands with
bash -cand does not export the plugin root as an environment variable for hook processes. The generator prefixes each command withCLAUDE_PLUGIN_ROOT=<ecc-root> ECC_PLUGIN_ROOT=<ecc-root>(env-prefix form), which the ECC hook bootstrap reads at startup. timeoutvalues are seconds in both formats and are preserved.
Generate the config
node scripts/dsh/generate-hooks-config.js --ecc-root /path/to/ECC --out ~/.dsh/ecc/hooks-dsh.json
The script validates nothing about your DSH install; it only converts
hooks/hooks.json into the bridge format and prints what it skipped.
Mount into a profile
Add a bare insert entry to the profile patch layer
(~/.dsh/profiles/<profile>/cordis.patch.yml). This mirrors how the bundled web
app preset mounts its plugins:
- insert:
- id: ecc-hooks-claude-code
name: "@deepseek-ai/dsh-hooks-claude-code"
config:
configPath: /absolute/path/to/hooks-dsh.json
Configuration notes from practice:
- A plain top-level entry (
- id: ...) is silently dropped; the loader only treatsinsertentries as additions. insertunder an existing non-group id is rejected ("not a group"); use a bare insert without a target id.- The plugin package does not need to be added to the profile
package.json; first-party plugins resolve from the DSH runtime install. - Validate without booting:
cd ~/.dsh && dsh --profile <profile> --dump-config(compose errors and dropped entries are reported on stderr).
Verify
# Compose check (no session boot). Keep stderr visible: silently dropped or
# rejected patch entries are reported there while the exit status stays 0.
cd ~/.dsh && dsh --profile web --dump-config > /tmp/dump.yml
grep ecc-hooks /tmp/dump.yml
# End-to-end: fire a SessionStart hook in a one-shot headless session
# (uses a test config with a single marker-writing hook)
dsh --profile headless --patch /tmp/ecc-patch-test.yml 'Reply with exactly: BOOT-OK'
A successful compose does not prove the entry mounted: dropped entries and "is not a group" rejections only appear on stderr, never in the exit status. Confirm the entry id exists in the dump and that stderr was empty.
In a live web session, the GateGuard fact-forcing hook denies the first edit/write/bash attempt until facts are presented — a visible signal that the bridge is active.
Updating
cd /path/to/ECC && git pull
node scripts/dsh/generate-hooks-config.js --ecc-root /path/to/ECC --out ~/.dsh/ecc/hooks-dsh.json
Linked skills reflect the pull immediately (symlinks), only the hooks config needs regeneration.
Scope
| Surface | Status on DSH |
|---|---|
| Skills | Native discovery; individual workflows retain their harness prerequisites |
| Hooks (23 command hooks, 5 of 7 events) | Works via the bridge; 3 events unsupported |
| Commands (slash-command surface) | Not available (Claude Code mechanism); workflows are covered by skills |
| Agents | Native dispatch unverified; use canonical prompt guidance only after review |
The validated setup here targets the CLI/web profile. Desktop profiles have a separate installation-owned runtime and skill discovery must be verified there independently. Generate hooks only from a reviewed ECC checkout; the linked checkout supplies their runtime.