Files
deepseek-harness/docs/cordis-catalog/services.md
Tianyi Cui 8bb8ac8b3c docs(tasks): condense background task prose
The background-task change repeated its lifecycle design across implemented RFCs, package READMEs, JSDoc, test commentary, and model-visible schemas. That repetition obscured the contracts that maintainers must preserve and added avoidable prompt tokens.

Rewrite the implemented RFCs around the current design, keep authorization, exact-owner cleanup, wait/abort ordering, producer quiescence, and teardown-failure guarantees at their owning surfaces, and remove peer surveys, review history, control-flow narration, and emphatic restatement.

Shorten the task and subagent schema wording, synchronize the bilingual tool cookbook, and regenerate the config, service, RFC, tool, and replay snapshot derivatives. Runtime behavior is unchanged; test edits update prose-only assertions and descriptions.
2026-07-15 21:08:58 +08:00

18 KiB

Cordis Services Catalog

Every ctx.<key> service a plugin can call: the exact public interface plus the class JSDoc. This is one axis of the wiring reference a plugin author works against — the events a plugin listens to are the sibling events catalog, and core-data-structures/ catalogs the data structures these signatures move around. An abstract seam (e.g. ctx.bash) is implemented by a separate package; the interface is what consumers code against.

This file is GENERATED from source (scripts/gen-cordis-catalog.ts) and verified fresh by pnpm run verify-cordis-catalog (part of doc-sync) — do not edit it by hand. Signature blocks use a ts cordis-catalog fence (skipped by doc-typecheck, since a bare signature is not standalone-compilable). Type names in a signature link to the page that documents them.

The harness tier below (the @deepseek-ai/dsh-* packages) is the vocabulary this repo owns. The inherited tier at the end is the cordis-core + loader/hmr/timer ctx surface a plugin also sees — pinned vendor source, summarized tersely.

ctx.agentLoop — AgentLoop

Concrete ReactLoopAgent factory and driver service.

create(id: AgentId, options: AgentOptions = {}, meta: Pick<SessionHeader, 'cwd'> = {}): ReactLoopAgent
async createAgent(ownerCtx: Context, options: CreateAgentOptions): Promise<AgentHandle>
async resume(ownerCtx: Context, options: ResumeAgentOptions): Promise<AgentHandle>

Source: packages/core/agent-loop/src/index.ts:335

ctx.agents — AgentRegistry

Agent registry (ctx.agents): tracks live agents so UI, hook, and orchestrator plugins can find them without depending on the concrete loop package. Agent creation is provided by whichever plugin implements the AgentFactory (@deepseek-ai/dsh-agent-loop), registered via setFactory.

setFactory(factory: AgentFactory): () => void
async create(options: CreateAgentOptions): Promise<AgentHandle>
async resume(options: ResumeAgentOptions): Promise<AgentHandle>
register(agent: Agent): () => void
enter(agent: Agent): () => void
announce(agent: Agent): void
get(id: AgentId): Agent | undefined
list(): Agent[]

Types: Agent

Source: packages/core/agent/src/index.ts:133

ctx.approval — ApprovalService

Approval service that applies session policy before answerers and logs every ask/outcome pair to the requesting session. It exposes deterministic policy changes to the model through prompt and pre-step notices.

async request(req: ApprovalRequest): Promise<ApprovalOutcome>

Types: ApprovalOutcome · ApprovalRequest

Source: packages/ui/user-approval/src/index.ts:229

ctx.bash — BashExecutor (abstract seam)

Abstract bash execution service. Subclass, implement the abstract methods, and load the subclass as a plugin — it registers as ctx.bash (one implementation per context; loading a second throws, which is cordis' standard duplicate-service behavior).

Implementations must honor these semantics:

  • run rejects only for infrastructure failures. Nonzero exits, timeout kills, and abort kills resolve with a BashRunResult.
  • start returns immediately; no timeout applies to background processes. done settles at process close and never rejects; spawn failures settle as killed with the error on stderr.
  • BashProcess.readOutput is incremental: consecutive reads never repeat output. Lossy reads report truncation and available spill files.
  • Disposal kills all running background processes and awaits their exit.
abstract resolve(request: BashExecRequest): BashExecSpec
abstract run(spec: BashExecSpec): Promise<BashRunResult>
abstract start(spec: BashExecSpec): BashProcess

Types: BashExecRequest · BashExecSpec · BashRunResult

Source: packages/bash/bash/src/index.ts:46

ctx.codeRuntime — CodeRuntime (abstract seam)

Registers one ctx.codeRuntime implementation. Program, budget, abort, and substrate failures resolve in CodeRunResult; only seam misuse rejects. Implementations bridge structured-cloneable bindings while treating programs as hostile peers, isolate runs from one another, and terminate and await in-flight runs during disposal.

abstract run(request: CodeRunRequest): Promise<CodeRunResult>

Types: CodeRunRequest · CodeRunResult

Source: packages/code-runtime/code-runtime/src/index.ts:30

ctx.compact — CompactService (abstract seam)

Abstract compaction service. Implementations own token estimation, retention, and summarization, but a successful run must replace the selected surface span with one summary node and prevent concurrent compaction of the same session. Load one implementation per context as ctx.compact.

abstract compactIfNeeded( agent: CompactAgentContext, fullSystemPrompt: string, sessionPrefix: readonly Message[], signal: AbortSignal, ): Promise<CompactionResult | null>
abstract compactRegion( session: Session, start: number, end: number, agent: CompactAgentContext, signal?: AbortSignal, ): Promise<CompactionResult>

Types: Message

Source: packages/compact/compact/src/index.ts:36

ctx.fs — FileSystem (abstract seam)

Abstract filesystem provider. Targets must preserve identity across aliases; reads expose regular UTF-8 text or typed errors, listings are stable and content-free, and mutations are atomic. Optional guards add stale protection without changing the unguarded provider contract.

abstract resolve(path: string, opts?: { cwd?: string }): Promise<FsTarget>
abstract stat(target: FsTarget, signal?: AbortSignal): Promise<FsInfo | undefined>
abstract readText(target: FsTarget, signal?: AbortSignal): Promise<string>
abstract streamText(target: FsTarget, signal?: AbortSignal): Promise<AsyncIterable<string>>
abstract listDir(target: FsTarget, signal?: AbortSignal): Promise<FsDirEntry[]>
abstract writeText(target: FsTarget, content: string, expected?: FsWriteIntent, signal?: AbortSignal): Promise<FsWriteOutcome>
abstract editText(target: FsTarget, edit: FsEditRequest, expected?: { version: FsVersion }, signal?: AbortSignal): Promise<FsEditOutcome>

Types: FsEditOutcome · FsEditRequest · FsInfo · FsTarget · FsVersion · FsWriteIntent · FsWriteOutcome

Source: packages/fs/fs/src/index.ts:78

ctx.llm — LlmService

The abstract llm service: an adapter registry plus a streaming model-call surface, interceptable via the llm/stream waterfall.

registerAdapter(models: string[], adapter: LlmAdapter): () => void
models(): string[]
stream(options: GenerateOptions): AsyncIterable<StreamChunk>

Types: GenerateOptions · StreamChunk

Source: packages/llm/llm/src/index.ts:75

ctx.permission — PermissionService

Owns the deployment's permission presets and their write path. Requires a confining ctx.bash executor and ctx.approval; unmatched knob values are reported as CUSTOM_PRESET, not an error.

current(events: readonly SessionEvent[]): string
resolve(name: string): PresetSpec
optionOf(name: string): PresetOption
set(session: Session, name: string): void

Types: SessionEvent

Source: packages/ui/permission/src/index.ts:94

ctx.sandbox — SandboxProvider (abstract seam)

Abstract process-sandbox service. confine must return enforcing argv or fail closed at wrap or runner-execution time; silent unconfined passthrough is forbidden. Functional probes arbitrate multi-runner chains and may be skipped for a sole candidate, whose own refusal remains the fail-closed end.

abstract confine(argv: readonly string[], policy: SandboxPolicy): ConfinedArgv

Types: ConfinedArgv · SandboxPolicy

Source: packages/sandbox/sandbox/src/index.ts:111

ctx.sessionPersistence — SessionPersistence (abstract seam)

Durable append-only session storage. Implementations preserve contiguous, losslessly JSON-serializable events; append resolves only after durability, and load balances a complete interrupted tail without rewriting committed events.

abstract create(meta: SessionHeader): Promise<void>
abstract append(id: SessionId, events: readonly SessionEvent[]): Promise<void>
abstract load(id: SessionId): Promise<{ meta: SessionHeader; events: SessionEvent[] }>
abstract list(): Promise<SessionHeader[]>

Types: SessionEvent

Source: packages/session-persistence/session-persistence/src/index.ts:30

ctx.sessionQuery — SessionQueryService

Live-preferred logical-corpus and exact-event read service.

listSessions(): Promise<SessionRecord[]>
async listEvents(sessionId: SessionId): Promise<SessionEventRecord[]>
async readEvent(request: SessionEventReadRequest): Promise<SessionEventWindow>

Source: packages/session-query/session-query/src/index.ts:35

ctx.sessions — SessionStore

In-memory session store (ctx.sessions).

Persistence is intentionally not implemented here — persistence plugins subscribe to session/event and flush on session/flush / dispose.

create(id?: SessionId, options?: CreateSessionOptions): Session
prepare(id?: SessionId, options?: CreateSessionOptions): Session
enter(session: Session): () => void
announce(session: Session): void
async flush(session: Session): Promise<void>
get(id: SessionId): Session | undefined
list(): Session[]
fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId): Session

Source: packages/core/session/src/index.ts:564

ctx.skills — SkillService

Registry of skill providers. It merges provider catalogs with stable first-wins duplicate handling, exposes sorted model-visible summaries, and loads full skill bodies on demand.

registerProvider(provider: SkillProvider): () => void
register(skill: SkillRegistration): () => void
async list(options: SkillLookupOptions = {}): Promise<SkillSummary[]>
async get(name: string, options: SkillLookupOptions = {}): Promise<SkillDefinition | undefined>

Source: packages/skill/skill/src/index.ts:141

ctx.subagents — SubagentService

Named provider registry and capability-checked start surface.

registerProvider(provider: SubagentProvider): () => void
getProvider(name: string): SubagentProvider | undefined
list(): string[]
async start(name: string, request: SubagentStartRequest): Promise<SubagentRun>

Source: packages/subagent/subagent/src/index.ts:141

ctx.systemPrompt — SystemPrompt

Registry service for the prompt inputs assembled before each model step.

section(section: PromptSection): () => void
tools(provider: (context: AssembleContext) => ToolProviderResult): () => void
variable(name: string, provider: (context: AssembleContext) => string | undefined): () => void
async assemble(context: AssembleContext = {}): Promise<PromptAssembly>

Source: packages/core/system-prompt/src/index.ts:209

ctx.tasks — TaskService

The tasks service: the runtime-global background task registry. See the module doc for the ownership, isolation, and lifecycle contracts.

start(spec: TaskStart): TaskId
list(caller?: Agent): TaskSnapshot[]
get(id: TaskId, caller?: Agent): TaskSnapshot
read(id: TaskId, caller?: Agent): TaskRead
kill(id: TaskId, caller?: Agent, reason?: string): 'requested' | 'already-terminal'
async wait(id: TaskId, timeoutMs: number, caller?: Agent, signal?: AbortSignal): Promise<TaskSnapshot>
onTaskDone(listener: TaskDoneListener): () => void
attachSurface(name: string): () => void

Types: Agent

Source: packages/tasks/tasks/src/index.ts:72

ctx.tools — ToolRegistry

Tool registry and execution pipeline. Scoped registrations shadow globals; one visibility resolver feeds presentation, lookup, and dispatch.

register(definition: ToolDefinition): () => void
restrict(filter: ToolRestriction): () => void
guard(guard: ToolGuard): () => void
get(name: string, scope?: ScopeKey): ToolDefinition | undefined
schemas(scope?: ScopeKey): ToolSchema[]
async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult>

Types: ToolDefinition · ToolExecutionInput · ToolExecutionResult

Source: packages/core/tools/src/index.ts:363

ctx.userInteraction — UserInteractionService

ctx.userInteraction: one active UI provider plus an ask() surface.

registerProvider(provider: UserInteractionProvider): () => void
async ask(request: AskUserQuestionRequest): Promise<AskUserQuestionAnswer>

Source: packages/ui/user-interaction/src/index.ts:82

ctx.web — WebService

The web access service. Registered as ctx.web (one instance per context).

Selection semantics (resolved at execution time, never order-dependent):

  • A configured id that is registered and available() → that provider.
  • A configured id not registered → WEB_PROVIDER_CONFIGURED_MISSING.
  • A configured id registered but unavailable → WEB_PROVIDER_CONFIGURED_UNAVAILABLE.
  • No id configured, exactly one registered usable provider → that provider.
  • No id configured, multiple usable providers → WEB_PROVIDER_AMBIGUOUS.
  • No id configured, no usable provider → WEB_PROVIDER_UNAVAILABLE.
registerSearchProvider(provider: WebSearchProvider): () => void
registerFetchProvider(provider: WebFetchProvider): () => void
async search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult>
async fetch(request: WebFetchRequest, signal?: AbortSignal): Promise<WebFetchResult>

Source: packages/web/web/src/index.ts:74

ctx.workflows — WorkflowService (abstract seam)

Workflow execution seam. Invalid requests throw before publication; a live run is holder-owned, its result never rejects, cancellation and disposal are bounded, and disposal waits for child cleanup within that bound. Lifecycle listener failures are contained, and workflow/end fires exactly once as the result settles.

abstract start(request: WorkflowStartRequest): WorkflowRun

Source: packages/workflow/workflow/src/index.ts:159

Inherited ctx members (cordis core + loader/hmr/timer)

The framework ctx surface every plugin also sees, beyond the harness services above. This is pinned vendor source (vendoring policy); it is summarized here so the page is a complete picture of what ctx offers, without elevating framework internals to the harness tier's prominence.