DeepSeek Harness Connector¶
Status: public-safe v0 connector for using DeepSeek Harness (dsh) as a
bounded agent execution host behind LoopX.
DeepSeek Harness is an open-source agent harness by DeepSeek AI. LoopX does not replace dsh's model loop, tools, sandbox, or session log. Instead, the connector lets LoopX govern one dsh-backed work segment at a time through the existing LoopX Turn protocol:
LoopX quota should-run
-> loopx turn run-once
-> loopx.dsh_goal_mode adapter (python -m loopx.dsh_goal_mode)
-> DeepSeek Harness Python SDK / dsh runtime
-> typed loopx_turn_result_v0
-> independent validator
-> LoopX writeback + quota spend
What This Connector Adds¶
- A thin adapter, now a first-class goal-mode subpackage at
loopx/dsh_goal_mode/(run withpython -m loopx.dsh_goal_mode; the historicalscripts/dsh_turn_host_adapter.pylauncher still works), that translatesloopx_turn_host_request_v0into one bounded dsh session prompt and parses the model's final JSON result back intoloopx_turn_result_v0. - A
deepseek-harnessagent type in LoopX onboarding so users can request the exact host instead of the genericother-agent. - Optional dependency
loopx[deepseek-harness]for the validateddeepseek-harness-sdk==0.1.5rc1Python client.
Install¶
Install LoopX's optional DeepSeek Harness extra:
The pin tracks the newest published dsh release channel rather than an
unreleased tag: 0.1.5rc1 for the PyPI SDK/runtime wheels and 0.1.5-rc.1 for
the npm @deepseek-ai/dsh latest tag. Upstream also publishes newer
next/alpha tags that are not the released channel. This release keeps the
Python client surface of the previously pinned 0.1.2a3 and moves the bundled
dsh runtime; LoopX selects the SDK's default sdk profile unless the operator
supplies an explicit cordis composition.
The DeepSeek Harness SDK spawns the bundled dsh-jsonrpc-agent runtime. It
uses the explicit adapter configuration plus normal provider environment
variables:
The adapter resolves its SDK home in this order: explicit --dsh-home, then
DSH_HOME, then <workspace>/.local/.dsh-sessions. It passes that path as the
SDK's dsh_home field; the SDK does not implicitly select ~/.dsh.
Prepare a dsh cordis.yml when the default bundled composition is not
appropriate. See the
DeepSeek Harness Python SDK reference
for runtime selection and configuration.
Onboard¶
loopx doctor --agent-type deepseek-harness
loopx agent-onboard \
--agent-type deepseek-harness \
--project . \
--goal-id <goal-id> \
--agent-id deepseek-worker \
--available-capability shell
deepseek-harness maps to the generic CLI agent loop and uses
--runtime-profile generic_cli in quota/heartbeat commands.
Run One Governed Turn¶
loopx turn run-once \
--goal-id <goal-id> \
--agent-id deepseek-worker \
--host generic-cli \
--execution-mode isolated-headless \
--project "$PWD" \
--host-adapter-command-json '["python3", "-m", "loopx.dsh_goal_mode", "--dsh-home", "/path/to/dsh-home", "--cordis", "/path/to/cordis.yml", "--model", "deepseek-v4-flash"]' \
--validation-command-json '["python3", "/path/to/verify-postcondition.py"]' \
--execute
The adapter uses <workspace>/.local/.dsh-sessions/ as its workspace-local
SDK home by default. Override it with --dsh-home <path>; the historical
--session-root spelling remains an adapter-command compatibility alias.
Session persistence itself is owned by the selected dsh composition and is not
implied by the home-directory name.
The headless adapter derives its local session id from a versioned digest of
[goal_id, agent_id, todo_id], preserving component positions so delimiters
inside an id cannot alias another lineage. The same lineage produces the same
id on retries; when all three components are absent, the existing Turn-key
fallback is retained. These opaque ids stay out of public LoopX state.
Upgrading from the former hyphen-joined naming scheme selects a new session id for a populated lineage. The adapter does not fall back to the ambiguous old name, rename sessions, or delete existing session files. Any persistence or resume behavior for the newly selected id remains owned by the dsh composition.
Run One Governed Turn In Process (--host dsh)¶
The built-in host runs the same adapter inside the CLI process:
loopx turn run-once \
--goal-id <goal-id> \
--agent-id deepseek-worker \
--host dsh \
--execution-mode isolated-headless \
--project "$PWD" \
--dsh-home /path/to/dsh-home \
--dsh-cordis /path/to/cordis.yml \
--dsh-model deepseek-v4-flash \
--validation-command-json '["python3", "/path/to/verify-postcondition.py"]' \
--execute
Unlike the subprocess mode, provider failures reach the Turn journal as typed
loopx_turn_host_failure_v0 kinds (including the SDK's exception-free
RunResult.finish_reason == "error" terminal report), so bounded same-Turn
retry stays available. This mode does not promise cross-turn dsh session
continuity or an outer wake/timer. See the adapter README for the home and
classification precedence, plus the hermetic verification smoke
(examples/loopx-turn-dsh-builtin-host-e2e-smoke.py).
Host Selection And Managed Executor Readback¶
The Turn host is selected, never inferred. dsh is the shipped default
because it is the managed execution unit the steward drives; LOOPX_TURN_HOST
re-points that default, and an explicit --host (or --host-adapter-command-json)
wins over both. A configured DEEPSEEK_API_KEY only authenticates the selected
host: discovering a credential never changes where a Turn runs.
Both loopx turn plan and loopx turn run-once report a managed_executor
block, so a caller reads the planned executor instead of inferring it from a
host id:
{
"schema_version": "managed_executor_binding_v0",
"executor": "dsh",
"executor_kind": "managed",
"credential_env": "DEEPSEEK_API_KEY",
"endpoint_env": "DEEPSEEK_BASE_URL",
"operator_credential_bound": true,
"available": true,
"unavailable_reason": null
}
executor_kind names where the Turn's model work is billed and bounded:
managed for a host bound to an operator credential, individual for a host
that runs on one person's own CLI login, and generic for a caller-supplied
adapter command. operator_credential_bound is the narrower claim: it is true
only when the operator credential or an explicit injected runner hook is
configured. available is false only when LoopX can prove the planned host
cannot launch here, and null for executors this projection does not probe
rather than an unproven claim. Only the credential variable name is reported;
the value is never read back.
run-once --execute fails closed on that verdict: status unavailable, no host
invocation, no journal write, and no quota spend, with
dsh_runtime_unavailable or operator_credential_unconfigured naming the
missing fact. plan reports the same verdict without refusing.
Boundaries¶
- LoopX keeps the durable goal, todo, claim, gate, quota, evidence, and scheduler authority.
- dsh owns model calls, tools, sandboxing, and the raw session log.
- The adapter must not publish raw transcripts, dsh JSONL sessions, credentials, local absolute paths, or unbounded tool output into LoopX state.
DeepSeekHarness.run()returns the candidate result; it is not proof of completion. An independent validator is required before LoopX writeback.- The dsh Python SDK is an optional dependency. Core LoopX remains runtime dependency-free.
- The adapter derives an owner-local session id, but LoopX does not project or validate a DSH Host Session Binding. This surface therefore does not claim a managed supervisor or cross-process resume guarantee.
Hermetic Validation¶
The repository includes four validation paths. The first three do not require the DeepSeek Harness SDK or a real dsh runtime:
python3 examples/dsh-turn-host-adapter-smoke.py
python3 examples/loopx-turn-dsh-e2e-smoke.py
python3 examples/loopx-turn-dsh-builtin-host-e2e-smoke.py
The first guards adapter translation and result shaping. The second drives the
full loopx turn run-once -> adapter -> fake dsh -> validator -> writeback ->
quota spend -> idempotent replay chain. The third proves the built-in host's
success path plus three bounded provider-capacity attempts, retry-budget
exhaustion without a fourth Host invocation, zero failure spend/writeback, and
provider-prose non-persistence.
The fourth uses the real deepseek-harness-sdk and the bundled dsh JSON-RPC
runtime. It still avoids a real model call by serving a local mock OpenAI-compatible
SSE endpoint, so it is hermetic and does not require DEEPSEEK_API_KEY:
python3 examples/loopx-turn-dsh-real-e2e-smoke.py --host generic-cli
python3 examples/loopx-turn-dsh-real-e2e-smoke.py --host dsh
The real-dsh smoke clears ambient DSH home variables and proves that both host paths can supply an explicit SDK home, start the actual dsh runtime, run one bounded turn through the real JSON-RPC agent loop, parse a typed JSON final message, and complete LoopX validation/writeback/quota spend.