DeepSeek Harness long tasks: DSH plugin background jobs

Configuration & UsagePublished 2026-10-03Author: DeepSeek Plugin Market
DeepSeek HarnessDSH pluginbackground jobsctx.jobsconfiguration
DeepSeek Harness runs tasks as background jobs: DSH plugin producers register in ctx.jobs with JobId <kind>-N, controlled via job_list, job_output, job_kill.

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:

  1. What counts as a job — built-in kinds include at least bash and subagent; JobKind derives from a declaration-mergeable map, so plugins can add their own kinds. Expected: builds, tests, and long delegations all land here.
  2. The id looks like <kind>-N — JobId is a branded id, and JobSpec.kind also acts as the id prefix. Expected: you can tell at a glance which kind of task it is.
  3. Access control is owner authorization — JobSpec.owner declares the owner session, and access is gated by that, not by id secrecy. Expected: treating a job id as a security measure is wrong.
  4. Producer and runtime split the work — JobSpec declares identity, owner session, an optional pull-based output source, and the launcher; after pre-checks the runtime calls run() with a JobHandle, 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:

  1. Watch live progress — the producer replaces the live progress line with JobHandle.updateProgress(line) (such as 3/10 or the current stage). Expected: progress is overwrite-style and cleared on settlement.
  2. Read the settlement reason — after settlement the terminal reason is in JobOutcome.detail. Expected: why a task ended and where it failed is here.
  3. 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; outputLimitBytes caps bytes per completion notification or output read, but it constrains the model-facing surface, not observers.
  4. Read the completion callback — JobHooks.done resolves 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:

  1. List and read — use job_list to find the target, then job_output to read its output. Expected: you can follow a long task's progress right in the session.
  2. Terminate — use job_kill to request termination, and JobStatus moves through stopping toward killed. Expected: termination is a request; wait for it to actually settle.
  3. 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.
  4. Ownerless jobs are looser — omitting owner creates 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.
  5. 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

  1. Do not treat a job id as a secret: access control relies on owner authorization; the id itself is not secrecy.
  2. done is not success: it is only a resource-release signal; read the settlement status and detail for the result.
  3. The output limit constrains the model-facing surface: outputLimitBytes does not change the ring's retention policy.
  4. Long tasks and subagents often appear together: delegating long work also becomes a job; see Use DeepSeek Harness subagents.
  5. 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

Which DeepSeek Harness operations become background jobs?

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.

Which states do DeepSeek Harness background jobs have?

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.

How do I view and control DeepSeek Harness background jobs?

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.

How is access to DeepSeek Harness background jobs controlled?

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.

Why does writing to a DeepSeek Harness job output sometimes fail silently?

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