Files
deepseek-harness/packages/shell/shell-env/README.md
T
Turtle bec6805d6a refactor(session-persistence)!: handle-based seam with a lifecycle-owned write path
The persistence seam is now create/open/stat/list returning per-session
SessionHandles (read/append/flush/close); every log read and write flows
through the owning handle. The seam package exports only the service and
handle contracts, consumer-visible errors, and pure durable-data
validation helpers; each backend owns its complete storage runtime, and
the shared contract suites pin equivalent observable behavior. The
backend routes published sessions' live events by id into the active
write handle; agent-loop only acquires, seeds, and closes the handle.
Resume appends interruptedTurnClosers through its write handle;
session-query owns the revision-keyed cold cache. Legacy-only surfaces
are removed in the same swap: locate/readRaw/supportsRawArtifacts, the
legacy event-shape read migration, zstd torn-frame salvage,
DSH_SESSION_JSONL, and hook transcript_path population; a torn final
zstd frame is discarded whole; the session-list cold blank probe returns
on stat metadata (eventCount derived from the last physical row,
sizeBytes). The WebUI ZIP export serializes the logical log from a read
handle, so both backends export identically.

Refs #3245
2026-09-01 23:19:02 +08:00

6.9 KiB

description, kind
description kind
The managed DSH_* shell environment for users and maintainers choosing, configuring, or extending the environment every model shell call runs with. package-reference

@deepseek-ai/dsh-shell-env

English | 中文

Summary

dsh-shell-env provides the trusted DSH_* environment that every model shell call — bash or pwsh — runs with: built-in facts such as DSH_HOME, DSH_SHELL=1, and the agent's DSH_SESSION_ID. Plugin authors can register their own facts with declared keys, collected per execution and disposed with their plugin; duplicate ownership or undeclared runtime keys fail loudly instead of silently overwriting. The registry changes nothing else the model sees — the shell tools own their own schemas and prompts. Choose it in any composition that mounts a model shell tool; configuration only picks the Harness home directory.

Table of Contents


Use this package

Load this plugin in any composition that mounts a model shell tool (dsh-tool-bash or dsh-tool-pwsh): each foreground or background shell call then runs with a freshly collected managed environment instead of whatever DSH_* values the process inherited.

What every shell call receives

Every call receives DSH_HOME (the absolute Harness home), DSH_SHELL=1, and, for agent calls, DSH_SESSION_ID (the calling session's id).

Adding your own environment facts

Other plugins contribute facts by registering a contributor with a stable name, the complete set of DSH_* keys it may return, a description per key, and a resolver that computes values for one execution:

import type { Context } from '@deepseek-ai/cordis'
import type {} from '@deepseek-ai/dsh-shell-env'

export const inject = ['shellEnv']

export function apply(ctx: Context): void {
  ctx.shellEnv.register({
    name: 'deployment-region',
    variables: { DSH_DEPLOYMENT_REGION: { description: 'Current deployment region.' } },
    resolve: execution => execution.agent === undefined ? {} : { DSH_DEPLOYMENT_REGION: 'cn-north' },
  })
}

Contributors must declare every key they return; returning an undeclared or non-string value fails the call. Registration is disposed with the registering plugin, so hot-reloading a plugin removes its facts.

Choosing the Harness home

The single config field picks the home directory exposed as DSH_HOME; the default resolution order is the dshHome config, then ambient $DSH_HOME, then ~/.dsh.

Field Default Meaning
dshHome $DSH_HOME, then ~/.dsh Absolute Harness home exposed as DSH_HOME

The generated configuration catalog is the exhaustive source for every accepted field and its JSDoc.

What can go wrong

Two contributors declaring the same key, or a contributor claiming a reserved built-in (DSH_HOME, DSH_SHELL, DSH_SESSION_ID), fails plugin load loudly. A DSH_* key must be all-caps with underscores (for example DSH_REGION), and a missing description fails registration.


Understand the implementation

Implementation internals — click to expand

This section explains the design decisions behind the registry and points at the code that realizes them; the observable behavior is fully covered in Use this package.

Design philosophy

  • Trusted namespace, rebuilt per call. The environment is a Harness-owned DSH_* namespace: the shell executor discards inherited DSH_* values and merges the registry's current snapshot for each execution, so nested harnesses and concurrent parent/child agents cannot leak stale identities, and process.env is never modified.
  • Declared ownership, loud conflicts. Contributors declare their keys up front so duplicate ownership is detected before the first command; resolvers may only return declared keys.
  • Built-ins stay here. DSH_HOME, DSH_SHELL, and DSH_SESSION_ID are reserved for the registry; contributors cannot claim them.

Source map

File Role
src/index.ts Plugin entry, ShellEnvRegistry service, and the built-in facts
No runtime invariant companion is published; the environment registry validates ownership and collected values at each registration/collection; it publishes no independent snapshot that a companion could cross-check.

Collection

collect(execution) starts from the built-ins, adds the session id when the execution carries an agent, then merges each registered contributor's resolved values sorted by contributor name. The result is a frozen, key-sorted snapshot passed through ShellExecRequest.dshEnv. list() enumerates declarations without running resolvers, so it cannot reflect execution-dependent values.


Further Exploration

Read these pages when the package-level contract is not enough. They move from the shell family to the executor seam and the generated catalogs.


Model Experience

Indirectly, through the shell tools (dsh-tool-bash, dsh-tool-pwsh), which expose this registry's managed DSH_* facts in every shell-tool call.

KV Cache effect

The managed environment never enters the request prefix, so it does not invalidate provider cache reuse; the shell tools' definitions and the current request envelope own any prefix change.

Known Limitations and Deferred Work

These limits define when the registry is a poor fit or needs care. They are current package constraints, not a task backlog.

  • list() enumerates plugin-contributed variables only — registry-owned built-ins (DSH_HOME, DSH_SHELL, DSH_SESSION_ID) are not included, so diagnostics, prompt, or UI code must not treat list() as an exhaustive environment catalog.

Dev Note

Working context for maintainers — click to expand

None.