Files
deepseek-harness/website/zh-CN/api/harness/events.md
2026-07-19 11:36:07 +08:00

621 lines
26 KiB
Markdown

<!-- Generated by scripts/gen-website-api.ts — do not edit by hand. Run `pnpm run gen-website-api` to regenerate. -->
# Harness events
Every event the harness packages declare on the cordis event bus (40 total), grouped by scope. The **mode** is the dispatch semantics (`emit` fire-and-forget, `parallel` awaited, `serial` first-bail, `waterfall` veto-chain — a waterfall listener MUST call `next()` to delegate).
## agent/*
### agent/created
**Mode:** `emit`
```ts website-api
'agent/created'(this: Scoped<Agent>, agent: Agent): void
```
A fully configured agent and live session were published. Setup is composition-only; `agent/session-start` is the first startup-driving seam. Synchronous listener failure vetoes publication, while returned-promise rejection is reported. Detach requested during dispatch waits until every creation listener has observed the stable entry.
- `agent` — the newly registered agent with its live session and completed setup. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/agent/src/types.ts#L141)
### agent/disposed
**Mode:** `emit`
```ts website-api
'agent/disposed'(this: Scoped<Agent>, agent: Agent): void
```
An agent left the registry; AgentLoop emits this after driver quiescence but before session detachment and scoped-registration unwind. Custom registry users own their driver-ordering contract.
- `agent` — the exact agent removed from the registry. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/agent/src/types.ts#L150)
### agent/error
**Mode:** `emit`
```ts website-api
'agent/error'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, error: Error): void
```
A step or turn errored. The loop reports a failure here (plus the logger) even when the error has no in-turn position for a session `error` event.
- `agent` — the agent whose turn errored.
- `turn` — the turn in which the failure surfaced.
- `step` — the step at which the failure surfaced.
- `error` — the failure, verbatim. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/agent/src/types.ts#L285)
### agent/pre-step
**Mode:** `serial`
```ts website-api
'agent/pre-step'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, fullSystemPrompt: string, sessionPrefix: readonly Message[], signal: AbortSignal): Promise<void> | void
```
Awaited serial checkpoint for session-surface mutation after prompt assembly and before `step/start`; appends land outside the pending step. The loop derives history once afterward, so compaction records and replacements are included without rewriting an assembled request. The prompt and prefix are the exact pressure inputs for that request, and `signal` cancels listener work. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
- `agent` — the agent opening the step.
- `turn` — the open turn number.
- `step` — the pending step number.
- `fullSystemPrompt` — the assembled prompt.
- `sessionPrefix` — the frozen request prefix.
- `signal` — the turn abort signal.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/agent/src/types.ts#L204)
### agent/prompt-submit
**Mode:** `waterfall`
```ts website-api
'agent/prompt-submit'(this: Scoped<Agent>, agent: Agent, content: ContentBlock[], source: MessageSource, next: () => Promise<PromptDecision>): Promise<PromptDecision>
```
Allow, rewrite, or block one drained prompt before it becomes a user message. Call `next()` for the unchanged default.
- `agent` — the agent draining its inbox.
- `content` — the drained message's blocks, as queued.
- `source` — the message's resolved source. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/agent/src/types.ts#L214)
### agent/queued
**Mode:** `emit`
```ts website-api
'agent/queued'(this: Scoped<Agent>, agent: Agent, content: ContentBlock[], info: { source: MessageSource; steering: boolean }): void
```
Detached, frozen content entered the agent's inbox. Source defaults have already been applied, so these are the exact values retained for the log.
- `agent` — the agent whose inbox received the message.
- `content` — the accepted content blocks retained by the inbox.
- `info` — the accepted source plus whether it entered as steering. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/agent/src/types.ts#L169)
### agent/request
**Mode:** `waterfall`
```ts website-api
'agent/request'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, config: LlmCallConfig, next: () => Promise<LlmCallConfig>): Promise<LlmCallConfig>
```
Replace the frozen call configuration. Model-visible content must use logged channels; this seam cannot mutate messages. Injection here joins the next request because the current step boundary is already fixed.
- `agent` — the agent making the model call.
- `turn` — the open turn number.
- `step` — the step whose request this is.
- `config` — the config the loop would use (frozen); return a replacement to switch. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/agent/src/types.ts#L226)
### agent/session-prefix
**Mode:** `waterfall`
```ts website-api
'agent/session-prefix'(this: Scoped<Agent>, agent: Agent, prefix: Message[], signal: AbortSignal, next: () => Promise<Message[]>): Promise<Message[]>
```
Compose request-only messages placed before derived history. The frozen result is computed once per loop instance, logged on its anchoring request header, and reused so the provider prefix remains stable. Interrupted composition is discarded. Composition precedes the first `agent/pre-step` and request boundary, so listener appends join the current request and pressure accounting sees the composed prefix. Changing context belongs in history; contributors should prepend to `await next()` to preserve registration order. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
- `agent` — the agent whose session prefix is being composed.
- `prefix` — the frozen seed; return an extended replacement.
- `signal` — aborts composition when the step is torn down.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/agent/src/types.ts#L241)
### agent/session-start
**Mode:** `emit`
```ts website-api
'agent/session-start'(this: Scoped<Agent>, agent: Agent, source: SessionStartSource): void
```
The session lifecycle began, once before the first turn. Use `agent.inject()` to seed model-facing context. This is a notification, not a veto; disposal requested by a lifecycle owner is rechecked before the driver starts.
- `agent` — the agent whose session lifecycle began.
- `source` — why the session started (fresh startup, resume, …). Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/agent/src/types.ts#L182)
### agent/status
**Mode:** `emit`
```ts website-api
'agent/status'(this: Scoped<Agent>, agent: Agent, status: AgentStatus): void
```
Agent status changed (`idle` ⇄ `running`, or → `disposed`). `send()` does not enter `running` synchronously; drive lifecycle from this event.
- `agent` — the agent whose status flipped.
- `status` — the status just entered (the transition's destination). Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/agent/src/types.ts#L159)
### agent/step-result
**Mode:** `waterfall`
```ts website-api
'agent/step-result'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, message: Message, next: () => Promise<Message>): Promise<Message>
```
Waterfall: post-process the assembled assistant Message before tool dispatch (validation, content rewriting, …).
- `agent` — the agent that received the step's response.
- `turn` — the open turn number.
- `step` — the step that produced the message.
- `message` — the assistant message as assembled from the stream. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/agent/src/types.ts#L252)
### agent/turn-continuation
**Mode:** `waterfall`
```ts website-api
'agent/turn-continuation'(this: Scoped<Agent>, agent: Agent, turn: number, defaultDecision: ContinuationDecision, next: () => Promise<ContinuationDecision>): Promise<ContinuationDecision>
```
Override whether the turn continues. The default continues after tool calls or steering and stops otherwise; a continue reason becomes steering.
- `agent` — the agent deciding whether to run another step.
- `turn` — the turn being continued or stopped.
- `defaultDecision` — what the loop would do absent an override. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/agent/src/types.ts#L262)
### agent/turn-stop
**Mode:** `serial`
```ts website-api
'agent/turn-stop'(this: Scoped<Agent>, agent: Agent, turn: number): ContinuationStop | undefined
```
Monotonic terminal-stop checkpoint after continuation and steering are folded; a stop remains authoritative through turn close and flush: steering queued in that window is discarded, while ordinary sends survive.
- `agent` — the agent whose composed continuation outcome may be stopped.
- `turn` — the turn at its terminal-stop checkpoint. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/agent/src/types.ts#L272)
## agent-loop/*
### agent-loop/config-start-failed
**Mode:** `emit`
```ts website-api
'agent-loop/config-start-failed'(sessionId: SessionId, error: unknown): void
```
A declarative agent entry failed before it could publish a live agent. Consumers that buffer work for the configured identity use this transient signal to reject that work instead of waiting forever. Normal factory teardown suppresses failures from the cancelled startup attempt.
- `sessionId` — exact shared agent/session identity that failed startup.
- `error` — persistence, setup, or publication failure.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/agent-loop/src/index.ts#L362)
## approval/*
### approval/request
**Mode:** `waterfall`
```ts website-api
'approval/request'(this: Scoped<ApprovalService>, req: ApprovalRequest, next: () => Promise<ApprovalOutcome>): Promise<ApprovalOutcome>
```
Ask composed answerers for one decision. Return an outcome to claim the request or call `next()`; failure yields the fail-closed default. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
- `req` — the pending decision (agent, tool identity, reason, signal).
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/ui/user-approval/src/index.ts#L31)
## fs/*
### fs/edit-intent
**Mode:** `waterfall`
```ts website-api
'fs/edit-intent'(target: FsTarget, actor: object | undefined, next: () => { version: FsVersion } | undefined | Promise<{ version: FsVersion } | undefined>): Promise<{ version: FsVersion } | undefined>
```
Single-slot decision for the next FileSystem.editText. Calling `next()` yields an unconditional edit; the first returned guard wins.
- `target` — the resolved target about to be edited.
- `actor` — the opaque tool-execution context the decider keys off.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/fs/fs/src/index.ts#L61)
### fs/observed
**Mode:** `emit`
```ts website-api
'fs/observed'(target: FsTarget, version: FsVersion, actor: object | undefined): void
```
Record a successful observation. Listeners must be synchronous recorders: throws fail the tool call and returned promises are not awaited.
- `target` — the target that was read/written/edited.
- `version` — the version the actor now holds as its observation.
- `actor` — the observing tool-execution context; undefined records nothing useful.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/fs/fs/src/index.ts#L70)
### fs/write-intent
**Mode:** `waterfall`
```ts website-api
'fs/write-intent'(target: FsTarget, actor: object | undefined, next: () => FsWriteIntent | undefined | Promise<FsWriteIntent | undefined>): Promise<FsWriteIntent | undefined>
```
Single-slot decision for the next FileSystem.writeText. Calling `next()` yields the bare provider's unconditional write; the first listener that returns an intent owns the decision rather than composing with peers.
- `target` — the resolved target about to be written.
- `actor` — the opaque tool-execution context the decider keys off.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/fs/fs/src/index.ts#L53)
## llm/*
### llm/stream
**Mode:** `waterfall`
```ts website-api
'llm/stream'(this: LlmService, options: GenerateOptions, next: () => AsyncIterable<StreamChunk>): AsyncIterable<StreamChunk>
```
Waterfall around every streaming model call (retry, replay, routing). Bound to the LlmService; call `next()` to reach the resolved adapter's stream, or yield your own chunks to short-circuit.
- `options` — the full request. A LOOP-built request arrives deep-frozen (mutation throws): its content is a pure function of the session log (the reconstructability RFC), so listeners read it, never rewrite it. A hand-built one-shot (compaction summarize) is the caller's own object and stays mutable here.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/llm/llm/src/index.ts#L40)
## session/*
### session/created
**Mode:** `emit`
```ts website-api
'session/created'(this: Scoped<Session>, session: Session): void
```
Creation announcement during session publication. A synchronous throw vetoes and rolls back with a paired disposal; detach requested during dispatch is deferred. A returned-promise rejection is logged but cannot retroactively veto this synchronous boundary. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only sessions entered through that agent's context.
- `session` — the session just entered and announced.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/session/src/index.ts#L47)
### session/disposed
**Mode:** `emit`
```ts website-api
'session/disposed'(this: Scoped<Session>, session: Session): void
```
Emitted once when an announced session leaves the store, including publication rollback, but never for an entry whose creation announcement did not begin. Listener failures are logged and contained. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`) reuses the owner scope.
- `session` — the session that is no longer live in the store.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/session/src/index.ts#L57)
### session/event
**Mode:** `emit`
```ts website-api
'session/event'(this: Scoped<Session>, session: Session, event: SessionEvent): void
```
Post-commit, fire-and-forget append feed. The listener snapshot resolves before the log push, but callbacks run after it; observer failures are logged and contained without making the committed append fail. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only events from sessions entered through that agent's context.
- `session` — the session whose log grew.
- `event` — the appended event, exactly as recorded.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/session/src/index.ts#L69)
### session/flush
**Mode:** `parallel`
```ts website-api
'session/flush'(this: Scoped<Session>, session: Session): Promise<void> | void
```
Awaited parallel durability checkpoint: every listener runs and the caller awaits all of them, with no waterfall veto. Dispatch through SessionStore.flush. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`) reuses the session's owner scope.
- `session` — the session whose buffered events must reach durable storage.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/session/src/index.ts#L79)
## subagent/*
### subagent/end
**Mode:** `emit`
```ts website-api
'subagent/end'(this: Scoped<SubagentService>, info: SubagentRunEndInfo): void
```
A ready child settled. Scope-filtered dispatch uses the same delegating parent carrier as `subagent/start`, so the lifecycle pair reaches the same scoped audience.
- `info` — the run identity and terminal outcome.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/subagent/subagent/src/index.ts#L112)
### subagent/provider-added
**Mode:** `emit`
```ts website-api
'subagent/provider-added'(provider: SubagentProvider): void
```
A provider became resolvable in the registry.
- `provider` — the registered provider.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/subagent/subagent/src/index.ts#L86)
### subagent/provider-removed
**Mode:** `emit`
```ts website-api
'subagent/provider-removed'(name: string): void
```
A provider left the registry. Accepted runs remain holder-owned.
- `name` — the provider name that no longer resolves.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/subagent/subagent/src/index.ts#L92)
### subagent/start
**Mode:** `emit`
```ts website-api
'subagent/start'(this: Scoped<SubagentService>, info: SubagentRunInfo): void
```
A provider established a ready child. For in-process providers, `ctx.agents.get(info.id)` resolves during this notification. Scope-filtered dispatch keys the carrier by the delegating parent, so a parent-scoped listener observes only its own delegations. Paired with `subagent/end`.
- `info` — the provider and ready child identity.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/subagent/subagent/src/index.ts#L103)
## system-prompt/*
### system-prompt/assemble
**Mode:** `waterfall`
```ts website-api
'system-prompt/assemble'(this: Scoped<SystemPrompt>, assembly: PromptAssembly, context: AssembleContext, next: () => Promise<PromptAssembly>): Promise<PromptAssembly>
```
Expert waterfall over the assembled sections, tools, and variables. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): scoped listeners receive only that scope's assemblies. The returned value is authoritative.
- `assembly` — the mutable assembly built from registered providers.
- `context` — the caller's per-assembly context.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/system-prompt/src/index.ts#L27)
### system-prompt/change
**Mode:** `emit`
```ts website-api
'system-prompt/change'(): void
```
Emitted when any prompt provider changes. This registry notification is unfiltered because a global change affects every scope.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/system-prompt/src/index.ts#L33)
## tools/*
### tools/change
**Mode:** `emit`
```ts website-api
'tools/change'(): void
```
A tool was registered or unregistered, or a scoped restriction changed (the available tool set changed — possibly for one scope only). An UNFILTERED registry-subject notification, deliberately not scope-filtered dispatch: a global change concerns every agent's next assembly, so a scoped listener subscribing here sees every change, not just its own scope's.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L116)
### tools/execute
**Mode:** `waterfall`
```ts website-api
'tools/execute'(this: Scoped<ToolRegistry>, exec: ToolExecution, next: () => Promise<ToolExecutionResult>): Promise<ToolExecutionResult>
```
Around-dispatch waterfall for timeout, retry, or metrics. `next()` returns a normalized result; wrappers may change only `exec.signal`, while call identity remains immutable. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls.
- `exec` — the allowed call about to dispatch (name, parsed arguments, caller agent, signal).
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L89)
### tools/post-execute
**Mode:** `waterfall`
```ts website-api
'tools/post-execute'(this: Scoped<ToolRegistry>, exec: ToolExecution, result: Readonly<ToolExecutionResult>, next: () => Promise<PostToolDecision>): Promise<PostToolDecision>
```
Accept, replace, enrich, or block a normalized dispatch result. `next()` accepts it unchanged; thrown tools still reach this seam as errors. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls.
- `exec` — the call that just ran (name, parsed arguments, caller agent).
- `result` — the dispatch outcome a listener may accept, replace, or block.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L98)
### tools/pre-execute
**Mode:** `waterfall`
```ts website-api
'tools/pre-execute'(this: Scoped<ToolRegistry>, exec: ToolExecution, next: () => Promise<PreToolDecision>): Promise<PreToolDecision>
```
Allow, deny, or ask before dispatch. `next()` delegates to allow; missing approval support turns `ask` into denial. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls.
- `exec` — the pending call (name, parsed arguments, caller agent).
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L80)
### tools/result
**Mode:** `emit`
```ts website-api
'tools/result'(this: Scoped<ToolRegistry>, exec: Readonly<ToolExecution>, result: Readonly<ToolExecutionResult>): undefined
```
Observe the frozen, lossless-JSON final outcome. Listener failures are contained. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): keyed by `exec.agent`.
- `exec` — the execution object that traversed the pipeline.
- `result` — a deep-frozen snapshot of the final returned result.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L106)
## workflow/*
### workflow/agent-end
**Mode:** `emit`
```ts website-api
'workflow/agent-end'(info: WorkflowRunInfo, agent: WorkflowAgentEndInfo): void
```
One `agent()` call settled (clean result, child failure, or run cancellation). Paired with Events['workflow/agent-start'] by `agent.seq`, exactly once per started call on every stop path — on an engine termination path (a worker killed past its grace) the end is engine-synthesized with outcome `'cancelled'`.
- `info` — the run's identity snapshot.
- `agent` — the call identity plus its outcome.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/workflow/workflow/src/index.ts#L81)
### workflow/agent-start
**Mode:** `emit`
```ts website-api
'workflow/agent-start'(info: WorkflowRunInfo, agent: WorkflowAgentInfo): void
```
One `agent()` call established a ready child run. Paired with Events['workflow/agent-end'] by `agent.seq`. A call that never receives a ready run from the provider emits neither event in this pair.
- `info` — the run's identity snapshot.
- `agent` — the call's sequence number, label, phase, and child id.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/workflow/workflow/src/index.ts#L70)
### workflow/end
**Mode:** `emit`
```ts website-api
'workflow/end'(info: WorkflowRunInfo, result: WorkflowResultInfo): void
```
A workflow run settled (any stop reason). Fired when WorkflowRun.result resolves. Paired with Events['workflow/start'].
- `info` — the run's identity snapshot.
- `result` — the outcome data (stop reason, error, agent count) — deliberately WITHOUT the result value (see `WorkflowResultInfo`).
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/workflow/workflow/src/index.ts#L91)
### workflow/log
**Mode:** `emit`
```ts website-api
'workflow/log'(info: WorkflowRunInfo, message: string): void
```
The script emitted a narration line (a `log(message)` call).
- `info` — the run's identity snapshot.
- `message` — the logged message, verbatim.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/workflow/workflow/src/index.ts#L60)
### workflow/phase
**Mode:** `emit`
```ts website-api
'workflow/phase'(info: WorkflowRunInfo, title: string): void
```
The script entered a phase (a `phase(title)` call) — progress grouping for observers; no execution semantics.
- `info` — the run's identity snapshot.
- `title` — the phase title, verbatim.
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/workflow/workflow/src/index.ts#L53)
### workflow/start
**Mode:** `emit`
```ts website-api
'workflow/start'(info: WorkflowRunInfo): void
```
A workflow run started — the script's meta block validated, the body about to execute. Paired with Events['workflow/end'].
- `info` — the run's identity snapshot (id + meta).
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/workflow/workflow/src/index.ts#L45)