Files
ECC/docs/DEEPSEEK-HARNESS-GUIDE.md
T

144 lines
5.7 KiB
Markdown

# DeepSeek Harness Guide
ECC runs on the [DeepSeek Harness](https://github.com/deepseek-ai/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-code`
plugin that ships inside the DSH runtime itself.
## Skills (automatic)
DSH loads skills from these roots (earlier roots win on name conflicts):
```text
<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:
```bash
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 -c` and does not export the plugin root as
an environment variable for hook processes. The generator prefixes each command
with `CLAUDE_PLUGIN_ROOT=<ecc-root> ECC_PLUGIN_ROOT=<ecc-root>` (env-prefix
form), which the ECC hook bootstrap reads at startup.
- `timeout` values are seconds in both formats and are preserved.
### Generate the config
```bash
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:
```yaml
- 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
treats `insert` entries as additions.
- `insert` under 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
```bash
# 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
```bash
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.