DEV Community

Ahab
Ahab

Posted on Originally published at indieseek.co

DeepSeek Harness 0.1.6 alpha headless automation: stdin, JSON events, and safe session resume

DeepSeek Harness 0.1.6 alpha headless automation: stdin, JSON events, and safe session resume

Quick answer

DeepSeek Harness 0.1.6-alpha.1 adds stdin tasks, newline-delimited JSON events, and session resume. Treat this as a Developer Preview contract, not stable GA. Pin the tag and commit, keep stdout as the machine channel, and accept a run only when it exits zero, emits one lossless final event, and emits no error event.

Who this is for

This guide is for developers putting dsh --profile headless behind CI, a job runner, or another agent. First complete the Developer Preview installation checklist and understand the session persistence model.

What changed and why now

DeepSeek published dsh-v0.1.6-alpha.1 on September 15, 2026. The official release adds three headless capabilities:

  • tasks from stdin;
  • exact session continuation with --session-id;
  • run events as newline-delimited JSON with --json.

The tagged source at commit 0a15e36e7f82b6ed45af6fa9759f29b40dcd965d adds stricter boundaries. A missing task reads stdin only when input is not a TTY. A bare - means stdin, but mixing it with task words is rejected. An unknown session ID fails instead of creating a conversation. Resume also refuses a different working directory, live session, fork or subagent session, or unsupported agent preset.

Define the run contract first

Run Invocation Receipt to retain
Fresh argument dsh --profile headless --json "run the tests" opening session event, raw event log, final event, exit code
Fresh stdin `printf '%s\n' "$TASK" \ dsh --profile headless --json -`
Continue dsh --profile headless --json --session-id "$SESSION_ID" "continue" exact session ID, same cwd, new events, flushed session

In JSON mode, stdout is the event stream, including structured errors; stderr remains diagnostic.

A fail-closed workflow

1. Pin the preview artifact and execution boundary

Record the binary, version, package digest, profile, working directory, and configuration hash. A newer alpha may change event fields or resume rules.

dsh --version
pwd -P
git rev-parse HEAD
Enter fullscreen mode Exit fullscreen mode

Run a disposable canary before granting production credentials or write access. Apply the tool and permission checklist separately; headless mode is not an authority boundary.

2. Preserve stdout, stderr, and exit status separately

set -o pipefail
printf '%s\n' "$TASK" | dsh --profile headless --json - \
  > run.events.ndjson 2> run.stderr.log
run_status=$?
Enter fullscreen mode Exit fullscreen mode

Never merge 2>&1 before parsing. Validate each stdout line and archive untouched NDJSON before transforming it.

3. Bind continuation to the opening event

The first session event contains sessionId and cwd. Extract one non-blank ID and store it with canonical cwd and task hash. Never manufacture an ID.

SESSION_ID=$(jq -r 'select(.type == "session") | .sessionId' \
  run.events.ndjson | head -n 1)
test -n "$SESSION_ID"
Enter fullscreen mode Exit fullscreen mode

Before resuming, compare pwd -P with stored cwd. A mismatch should fail before tools reach the wrong repository.

4. Reconcile event pairs, not just text

The stream can include status, thinking, text, tool_call, tool_result, final, and error. Match every tool_result.callId to one prior tool_call.callId. Treat a missing result, duplicate ID, error event, or incomplete final as a hold.

Non-final event strings are capped at 8 KiB and non-final lines at 32 KiB; oversized data can carry truncated: true. The final event is intentionally lossless. Therefore, never use a truncated tool result as the only proof of a deployment, payment, or destructive action—verify the target system directly.

5. Gate on terminal evidence

A completed run requires all of these:

  • process exit status 0;
  • exactly one opening session event with the expected cwd;
  • valid NDJSON on every stdout line;
  • no error event;
  • exactly one non-empty final event;
  • all required tool calls reconciled with results;
  • external state independently verified when the task changes another system.

The tagged implementation exits 0 only when the turn reason is completed; other terminal reasons exit 1. Keep that status even if useful text appeared earlier.

Eight-case acceptance matrix

Case Expected result
Fresh argument task New session event, ordered events, final event, exit 0
Fresh stdin task Same contract without shell interpolation changing the task
Empty task on a TTY Usage failure, not a hanging automation
- mixed with task words Rejected as ambiguous input
Unknown session ID Failure with no replacement session created
Resume from another cwd Failure before tools can act in the wrong workspace
Oversized non-final payload truncated: true; final output remains lossless
Model or tool failure Error event and non-zero exit; no success receipt

Copyable run receipt

date / runner / change ticket:
dsh version / package digest / profile:
canonical cwd / repository revision:
task source: argument | stdin
task sha256:
session id / fresh or resumed:
event log sha256 / stderr log sha256:
tool_call count / reconciled tool_result count:
truncated events / external verification:
final event present / exit status:
decision: hold | retry-same-session | accepted
Enter fullscreen mode Exit fullscreen mode

Common mistakes

  • Calling an alpha release stable because the command worked once.
  • Parsing pretty text instead of retaining the raw NDJSON stream.
  • Taking a session ID from a filename or log label rather than the opening event.
  • Resuming from a different cwd or silently replacing an unknown session.
  • Treating a tool_result or final paragraph as proof of external success without reading the target system.

Building something? Turn your product page into a show people want to watch with PromoFast—hosted, embeddable, and ready to export.

FAQ

Is the JSON output one document?

No. It is newline-delimited JSON: parse and validate one event per line.

Can a misspelled session ID start a new run?

No. The tagged startup code rejects an unknown ID and tells the caller to omit it when intentionally creating a new session.

Does --json make tool results complete?

Not always. Large non-final events may be truncated. The final event is lossless, but external side effects still need direct verification.

Is headless mode a sandbox?

No. It changes input and output handling. Tool permissions, credentials, filesystem boundaries, and network access remain separate controls.

Sources


Originally published on IndieSeek.

Top comments (0)