Skip to content

Python SDK & CLI

Dipanshu Kamboj edited this page Aug 31, 2026 · 1 revision

🐍 Python SDK & CLI

Two ways to drive the harness without the browser: the CLI launcher for humans, and the Python SDK for code.

The dsh CLI

pnpm dsh web                    # browser UI at http://127.0.0.1:2323
pnpm dsh --profile headless "run the recon sweep and print findings"
pnpm dsh --profile <name>       # boot a named profile under $DSH_HOME/profiles/<name>
pnpm dsh plugin --profile <name> <pnpm args>   # manage a profile's plugins
  • The invoking directory is the default workspace root.
  • Launcher flags come first; anything the launcher doesn't recognize belongs to the booted app (dsh --profile web --port 8080).
  • web and headless profiles auto-initialize from shipped templates; custom profiles are created through dsh plugin.
  • Inspect a composed tree without booting: --dump-default-config / --dump-config.

Headless mode is the scripted path: one fresh persisted session, the final answer on stdout, exit code reflects success — CI-friendly.

Profiles — the launcher's superpower

A profile is an ordered stack of bundle patch layers under your own override layer:

root (empty)
 └─ bundle patches (dsh.profile.bundles, in order)
     └─ profile cordis.patch.yml
         └─ home cordis.patch.yml ($DSH_HOME)
             └─ --patch overlays

web and headless are shipped bundles; anything else (TUI, team profile, your pentest preset) is a profile you build with dsh plugin.

Python SDK

Drive the same runtime over JSON-RPC stdio from Python — real model endpoints, sessions, and tools, no browser.

python -m pip install deepseek-harness-sdk
from deepseek_harness import DeepSeekHarness

with DeepSeekHarness() as harness:
    result = harness.run("Enumerate the target's live subdomains and list HTTP ones.")
with DeepSeekHarness(
    provider="deepseek-official",
    model="deepseek-v4-flash",
    max_tokens=49_152,
    cordis="examples/jsonrpc-agent/cordis.yml",   # your own composition
) as harness:
    result = harness.run("Make the requested code change.")

What Session.run() returns — RunResult(session_id, final_response, finish_reason, events, notifications, session_root):

  • final_response — the last committed root-session assistant text of the run interval.
  • finish_reason — completed, max-tokens, error, … from the interval's last turn end (None when no turn ended).
  • events — root-session events only (descendants can't overwrite your answer).
  • notifications — root and all known subagent descendants, in wire order — watch nested subagent lifecycle live.

The runtime subprocess is reused across calls (context manager or close()); the bundled composition ships the JSON-RPC server, agent core, DeepSeek adapter, JSONL persistence with semantic checkpoints, and local bash. Any composition of your own works too — keep the @pentest-harness/dsh-sdk-jsonrpc-server entry and pass cordis=….

Environment wiring: DEEPSEEK_BASE_URL / DEEPSEEK_API_KEY (or any provider your composition registers) — point them at real endpoints or a local proxy.

When to use which

Web UI headless CLI Python SDK
Interactive hunting ✅ best – –
CI / scripted runs – ✅ ✅
Programmatic control of sessions – – ✅
Subagent event streams ✅ ✅ ✅ (notifications)

Clone this wiki locally