Files
deepseek-harness/docs/rfc/proposed/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md
T
Tianyi Cui e13bbcb5d5 docs(rfc): propose nine simplification RFCs from a five-domain survey
Survey of master for surface area whose consumers are tests/docs only,
classified per candidate (production vs non-production corpus, rg + call-site
reads). New proposed/simplification RFCs:

- prune-producerless-vocabulary-variants: CacheHint/cache? fields,
  MessageSource 'agent', TurnTrigger 'continuation' (the TurnEndReasonMap
  omitted-until-emitted policy, applied)
- drop-inert-request-knobs: GenerateOptions.prefill (both adapters throw
  UNSUPPORTED), ToolSchema.strict (zero setters; beta-URL-only feature)
- drop-web-providers-change-event: the llm/adapter-change precedent replayed
- drop-image-content-block: no producer; every consumer silently drops it
- prune-write-only-fs-surface: fs-local STREAM_MIN_SIZE/streamMinSize,
  FsTarget.inputPath, FsEditOutcome.replacements/replaceAll,
  FileReadOutcome.limit/version
- prune-unimplemented-subagent-vocabulary: outputSchema/structured,
  toolFilter, sendMessage/resume (depthLimit stays)
- trim-acp-bridge-unreachable-surface: agentName/agentVersion knobs
  (resolves TODO(double-default)), toolKindFor name-sniffing
- prune-dead-core-spine-surface: SurfaceManager.invalidate(), runLoop/Inbox
  exports, ToolExecutionResult.callId
- share-app-bin-boot-glue: the twin coverage-exempt bin helpers

Also supplements three existing proposed RFCs with survey evidence: the bash
seam consumption census (generic-long-running-tool-runtime), three more
static inventories (discover-package-inventory), and the bridge's already-1:1
id usage (unify-agent-and-session-id).
2026-07-04 03:00:25 +08:00

4.3 KiB

RFC: Prune the unimplemented subagent seam vocabulary

Status: proposed

Problem

The subagent seam shipped a two-tier capability design: start-time capability flags checked by the service, and optional runtime methods on SubagentRun. Three start-time features and both optional runtime methods have zero implementations and zero callers:

  • outputSchema/structured and toolFilter (SubagentCapabilities, SubagentStartRequest, SubagentResult in packages/subagent/subagent/src/types.ts): every real provider declares outputSchema: false, toolFilter: false (packages/subagent/subagent-spawn/src/index.ts, packages/subagent/subagent-fork/src/index.ts, packages/subagent/subagent-acp/src/index.ts); the sole production ctx.subagents.start caller (packages/subagent/tool-subagent/src/index.ts) builds { prompt, parent, signal?, agentOptions? } and structurally cannot set either; structured is produced only by the test mock (packages/support/subagent-mock) for its own spec. The service's capability check carries two assert rows whose only exercisers are the rejection tests.
  • SubagentRun.sendMessage / SubagentRun.resume (same file): implemented by NO provider — not even the mock; the spawn spec asserts their absence.

The only reason dsh-subagent depends on dsh-tools at all is outputSchema's SchemaSpec type. Three subsequent subagent workstreams (per-session snapshot replay, the fork seed boundary, the ACP backend) landed around this surface without growing a single consumer.

Proposal

Remove outputSchema/structured, toolFilter, sendMessage, and resume from the seam; shrink SubagentCapabilities to { depthLimit }; drop the two capability-assert rows, the all-false flags on the three providers, the mock's structured branch and its capabilities/structured config knobs, and the tests that exist to pin the removed surface (the two rejection rows, the spawn absence test, the mock structured specs). Drop the dsh-tools peer/dev dependency from packages/subagent/subagent/package.json. Update the subagent.md pastes and the type-equiv manifest, and the README rows in packages/subagent/subagent, packages/subagent/subagent-spawn, packages/subagent/subagent-fork, and packages/support/subagent-mock. The implementing PR amends the seam RFC's capability catalog per implemented/AGENTS.md.

Keep depthLimit/maxDepth and the capability-check mechanism itself: the in-process backend genuinely enforces the cap (SubagentDepthError in packages/subagent/subagent-inprocess/src/index.ts), recursion is the seam RFC's named risk, and one live capability row keeps the two-tier design demonstrated rather than merely remembered.

This is the seam-vocabulary echo of prune dead methods from the persistence seam: members every implementation must declare for nobody — weaker even, since here zero implementations exist.

Why not keep it?

The two-kinds-of-capability design is the seam RFC's headline, and re-adding outputSchema later touches several files. But the design survives with depthLimit as its live example and the RFCs as its record, and the seam RFC itself concedes the shipped toolFilter shape is wrong (real enforcement needs a tools/execute veto, not schema filtering) — re-adding against a real implementing provider will pin a better contract than the current speculative one.

Acceptance criteria

  • The removed spellings appear only in this RFC and the amended seam RFCs; SubagentCapabilities is { depthLimit: boolean }; the dsh-tools dependency edge is gone (hygiene green).
  • Depth-enforcement tests are unchanged and green.

Risks

The in-flight hooks stack enriches subagent lifecycle event payloads (agent type, last assistant message) — adjacent files, no field overlap; coordinate landing order mechanically. Worth recording while here: nothing production sets maxDepth today (tool-subagent exposes no knob for it), so in-process recursion is uncapped — wiring the depth machinery this RFC keeps is a small feature gap, and an argument for keeping it, not for cutting it.