DeepSeek Harness long tasks: DSH plugin background jobs
DeepSeek Harness manages long tasks through a background jobs runtime: producers such as bash and subagent register jobs in ctx.jobs, JobId looks like <kind>-N, status is one of running, stopping, completed, killed, or failed, and the model can view and control them with job_list, job_output, and job_kill (source).
What a DeepSeek Harness background job is: long tasks and ctx.jobs
When work runs long and should not block the conversation, it is registered as a job; the runtime holds identity, access control, lifecycle state, and the output ring, while execution resources belong to the producer (source). Key points:
- What counts as a job — built-in kinds include at least
bashandsubagent;JobKindderives from a declaration-mergeable map, so plugins can add their own kinds. Expected: builds, tests, and long delegations all land here. - The id looks like
<kind>-N—JobIdis a branded id, andJobSpec.kindalso acts as the id prefix. Expected: you can tell at a glance which kind of task it is. - Access control is owner authorization —
JobSpec.ownerdeclares the owner session, and access is gated by that, not by id secrecy. Expected: treating a job id as a security measure is wrong. - Producer and runtime split the work —
JobSpecdeclares identity, owner session, an optional pull-basedoutputsource, and the launcher; after pre-checks the runtime callsrun()with aJobHandle, and after registration commits it performs no step that could fail. Expected: if pre-checks fail, nothing is registered.
How to read DeepSeek Harness background job status and progress
JobStatus is one of running, stopping, completed, killed, or failed; producer-specific facts go into JobView.progress while running and into JobView.detail once settled (source). How to observe:
- Watch live progress — the producer replaces the live progress line with
JobHandle.updateProgress(line)(such as3/10or the current stage). Expected: progress is overwrite-style and cleared on settlement. - Read the settlement reason — after settlement the terminal reason is in
JobOutcome.detail. Expected: why a task ended and where it failed is here. - Read the output ring — the producer appends output chunk by chunk with
JobHandle.append(text), with offsets advancing by UTF-8 bytes. Expected: the model reads what is in the ring;outputLimitBytescaps bytes per completion notification or output read, but it constrains the model-facing surface, not observers. - Read the completion callback —
JobHooks.doneresolves when the producer releases resources, not when the work finishes. Expected: do not treat done as a "task succeeded" signal.
DeepSeek Harness job control and cleanup: job_list, job_output, job_kill
Three model-facing tools are available: job_list lists jobs, job_output reads output, and job_kill requests termination; termination must be synchronous, idempotent, and eventually settle done (source). Control points:
- List and read — use
job_listto find the target, thenjob_outputto read its output. Expected: you can follow a long task's progress right in the session. - Terminate — use
job_killto request termination, andJobStatusmoves throughstoppingtowardkilled. Expected: termination is a request; wait for it to actually settle. - Destroying the owner cancels too — once the owner's currently registered live Agent is destroyed, its jobs are cancelled and awaited. Expected: ending a session wraps up the tasks under its name.
- Ownerless jobs are looser — omitting
ownercreates an ownerless job open to any caller until the service is destroyed. Expected: use it with care; such tasks are not protected by a session fence. - Writes after settlement are dropped — after a job settles (the producer finished on its own, it was killed, or the registry tore it down), later writes do not throw; they are recorded and dropped. Expected: a producer's final flush does not break its own cleanup path.
To see how the community extends long tasks and task panels with plugins, browse DSH Plugin Hub.
Notes and common questions
- Do not treat a job id as a secret: access control relies on owner authorization; the id itself is not secrecy.
doneis not success: it is only a resource-release signal; read the settlement status anddetailfor the result.- The output limit constrains the model-facing surface:
outputLimitBytesdoes not change the ring's retention policy. - Long tasks and subagents often appear together: delegating long work also becomes a job; see Use DeepSeek Harness subagents.
- Starting tasks in CI and other non-interactive contexts: mind the exit semantics; see Run dsh plugin commands in scripts and CI.
Sources: Background jobs runtime (official docs), Tool schema catalog (official docs)
FAQ
In DeepSeek Harness, long-running producers register as jobs; built-in kinds include at least bash and subagent. JobKind derives from a declaration-mergeable map, so plugins can add their own kinds, and the registry treats each kind as an opaque id namespace.
In DeepSeek Harness, JobStatus is one of running, stopping, completed, killed, or failed. Producer-specific facts go into JobView.progress while running and into JobView.detail once settled.
DeepSeek Harness exposes three model-facing tools: job_list, job_output, and job_kill — the first lists jobs, the second reads output, the third requests termination. A termination request must be synchronous, idempotent, and eventually settle the matching done.
Access to DeepSeek Harness background jobs is through owner authorization, not id secrecy: JobSpec can declare an owner session, and once the owner's currently registered live Agent is destroyed its jobs are cancelled and awaited. Omitting owner creates an ownerless job open to any caller until the service is destroyed.
In DeepSeek Harness, after a job settles (the producer finished on its own, it was killed, or the registry tore it down), later writes do not throw; they are recorded and dropped, so a producer's final flush does not break its own cleanup path.
Related Terms
- ctx.jobs
- ctx.jobs is the background job registry service of DeepSeek Harness; long-running producers register jobs through it, and the runtime holds identity, access control, lifecycle state, and the output ring centrally.— DeepSeek Harness Documentation - Background jobs runtime
- JobId
- JobId is the branded identifier of a background job, generated as <kind>-N; access control relies on owner authorization rather than id secrecy, so a job id is not a security measure.— DeepSeek Harness Documentation - Background jobs runtime
- JobStatus
- JobStatus is the lifecycle state of a job, one of running, stopping, completed, killed, or failed; running progress lands in JobView.progress and settlement details in JobView.detail.— DeepSeek Harness Documentation - Background jobs runtime
- JobHandle
- JobHandle is the surface handed to a producer, offering append to add chunks to the output ring and updateProgress to update the live progress line; its methods are synchronous and valid throughout the job's lifetime.— DeepSeek Harness Documentation - Background jobs runtime
Sources
- DeepSeek Harness Documentation - Background jobs runtime· deepseek-harness
- DeepSeek Harness Documentation - Tool schema catalog· deepseek-harness