Repository navigation
Python SDK & CLI
Two ways to drive the harness without the browser: the CLI launcher for humans, and the Python SDK for code.
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). -
webandheadlessprofiles auto-initialize from shipped templates; custom profiles are created throughdsh 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.
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.
Drive the same runtime over JSON-RPC stdio from Python — real model endpoints, sessions, and tools, no browser.
python -m pip install deepseek-harness-sdkfrom 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 (Nonewhen 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.
| Web UI | headless CLI | Python SDK | |
|---|---|---|---|
| Interactive hunting | ✅ best | – | – |
| CI / scripted runs | – | ✅ | ✅ |
| Programmatic control of sessions | – | – | ✅ |
| Subagent event streams | ✅ | ✅ | ✅ (notifications) |