DeepSeek Harness Python SDK quickstart
August 28, 2026 · View on GitHub
The rc.2 Python SDK is a programmatic alternative to the Web UI. It starts a bundled Harness runtime, runs a checked-in Agent composition, and returns a structured result to Python.
Restart recovery: session/prompt is not a resume operation
The Python SDK 0.1.1rc1 has an important restart boundary. A session/prompt call with an ID that was persisted before a Harness restart can fail with id collision: the SDK server calls agents.create() again, while the persistence layer expects an existing log to be opened through a resume path. In-process continuation works; cross-restart continuation does not. This is tracked in upstream discussion #4954.
Treat a restart as a state-recovery decision, not as a normal retry:
- Keep the original session ID and the exact
dsh_homeso the failure is reproducible. - Capture the structured
turn/enderror and the persisted log before changing files. - Do not overwrite the log and retry the same
session/prompt; that only repeats creation against an existing ID. - If the task can tolerate losing harness-internal state, use a copied profile and replay the client-owned conversation history as content blocks with a new session ID.
- Verify that the recovered turn has the expected visible context, and record that tool results, summaries, and other runtime state were not restored.
The replay workaround is intentionally lossy. A safe client should expose resume unavailable as a distinct state, preserve the original artifact, and request an explicit SDK resume/open method rather than silently clearing a user's session. Acceptance requires: same-ID in-process continuation succeeds; same-ID after restart produces a classified error; the original log remains intact; and the fallback path creates a new ID only after the user or operator accepts the loss of internal state.
Important
This page is pinned to the rc.2 source snapshot. The current 0.1.2-alpha.1 source tree no longer includes examples/jsonrpc-agent; do not expect the commands below to work unchanged after cloning current master.
Prerequisites
- Python 3.10 or newer;
- Git;
- Linux x64/arm64 or macOS 14+ on Apple silicon;
- a DeepSeek-compatible endpoint and credential;
- a disposable workspace the Agent may modify.
The published SDK bundles its runtime, so the installed package does not require system Node.js.
Install in a virtual environment
git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
python -m venv .venv
. .venv/bin/activate
python -m pip install deepseek-harness-sdk
Configure the model route
export DEEPSEEK_API_KEY=sk-your-key-here
# export DEEPSEEK_BASE_URL=http://127.0.0.1:8000/v1
# export DSH_MODEL=deepseek-v4-flash
Keep real credentials out of shell history, repositories, screenshots, and issue reports. Use an isolated key with a spending limit.
Run the checked-in example
python examples/jsonrpc-agent/minimal.py \
--workspace /absolute/path/to/workspace \
--session-root /absolute/path/to/sessions \
--session-id example-001 \
"Inspect the repository and explain the failing tests. Do not modify files."
The script prints the final assistant response. The session root receives a JSONL log containing assembled requests and tool activity.
Call it from Python
from pathlib import Path
from deepseek_harness import DeepSeekHarness
config = Path("examples/jsonrpc-agent/minimal.cordis.yml").resolve()
workspace = Path("/absolute/path/to/workspace").resolve()
sessions = Path("/absolute/path/to/sessions").resolve()
with DeepSeekHarness(
provider="deepseek-official",
model="deepseek-v4-flash",
max_tokens=49_152,
cwd=str(workspace),
session_root=str(sessions),
cordis=str(config),
) as harness:
result = harness.run(
"Inspect the repository and explain the failing tests. Do not modify files.",
session_id="example-001",
)
print(result.final_response)
The context manager starts the runtime lazily and reuses it until exit. Reusing the same session_id continues the durable conversation and its persistent Bash process; use a fresh ID for independent work.
Understand the security boundary
The official minimal composition currently uses danger-full-access. Its persistent Bash and editor can modify any path the runtime process can access. A polite “do not modify files” prompt is useful intent, but it is not a security boundary.
For exploratory runs:
- use a disposable checkout or container;
- mount only required data;
- use a fresh session ID;
- inspect the JSONL session log;
- delete the test workspace and rotate exposed credentials if needed.
The persistent PTY requires a POSIX terminal substrate; this example does not support Windows Agents.
Success evidence
- the process exits normally;
result.final_responsecontains the final text;- the chosen session directory contains a JSONL log;
- the response refers to files inside the intended workspace;
- no unapproved mutation occurred outside the disposable environment.