* test(#3673): add failing tests for dispatch.maxConcurrency axis and dispatch-capacity CLI route Extends tests/host-integration.test.cjs with negotiateHostCapabilities maxConcurrency negotiation coverage (test matrix rows 1-15, including a fast-check property test) and a new #3673 dispatch-capacity CLI route describe block spawning the real gsd-tools.cjs (rows 16-25). Extends tests/host-integration-validator-parity.test.cjs with an all-19-descriptor maxConcurrency presence/validity sweep (row 26) and adds a hostile-input validator test to host-integration.test.cjs (row 27). The dispatch.maxConcurrency field does not exist yet, so these tests fail. * feat(#3673): add dispatch.maxConcurrency axis, negotiation, validator parity, and the dispatch-capacity query Adds a numeric dispatch.maxConcurrency sub-field to the Host-Integration Interface (ADR-1239 Phase 1), following the existing dispatch.isolation sub-field pattern: DispatchCapability interface, SAFE_DEFAULTS/PROFILE_BASELINES floors, and a negotiateHostCapabilities branch that passes through a positive safe integer and fails closed to 1 otherwise (no engine-side reduction, per the design doc's explicit rejection of a min(host,engine) rule). capability-validator.cjs gains parity validation for the new field (optional, positive safe integer or the "undocumented" sentinel — mirroring isolation's "added after existing descriptors" treatment). gsd-tools.cjs gains a new `query dispatch-capacity` route, a pure-read sibling of `dispatch-isolation` with no side effects: live env (GSD_DISPATCH_MAX_CONCURRENCY) > descriptor > fallback-to-1 precedence. All 19 capabilities/*/capability.json descriptors now declare dispatch.maxConcurrency: claude carries the one cited value (20, per code.claude.com/docs/en/sub-agents); the other 18 carry "undocumented" (not yet researched for this axis). * docs(#3673): document dispatch.maxConcurrency and add its citation row to the capability matrix Updates docs/reference/host-integration-interface.md's dispatch struct entry (also backfilling the previously-undocumented isolation/backgroundDispatch sub-fields found stale in the same table) and adds fail-closed/live-transport precedence prose for the new maxConcurrency field. Adds a dispatch.maxConcurrency row (with citation) to all 19 host sections in docs/reference/host-integration-capability-matrix.md — required for tests/host-integration-descriptors.test.cjs's kimi-code matrix-parity check, which asserts every declared dispatch sub-axis is documented there. Updates docs/how-to/add-or-update-a-host-integration.md's dispatch checklist and example descriptor block to mention maxConcurrency (and, likewise backfilling a stale gap, isolation/backgroundDispatch). * fix(#3673): extract shared maxConcurrency validator, drop dead reserved-name check Exports isPositiveSafeInteger from src/host-integration.cts as the single source of truth for the dispatch.maxConcurrency positive-safe-integer contract; negotiateHostCapabilities and gsd-tools.cjs's routeDispatchCapacity now both call it instead of independently reimplementing the same predicate. Also removes the __proto__/constructor/prototype reserved-name branch from capability-validator.cjs's maxConcurrency check — copy-pasted from the string-enum fields above it, but unreachable for a numeric field (the generic positive-safe-integer branch already rejects any string) and absent from maxDepth, the field the code's own comment claims to mirror. --------- Co-authored-by: sim <sim@local>
5.3 KiB
Reference: the Host-Integration Interface
This is the normative reference for the GSD Host-Integration Interface (ADR-1239)
— the versioned, negotiated contract over which any host embeds GSD's
orchestration loop. The published surface is the SDK entry
(src/host-integration-sdk.cts); this document specifies every symbol on it.
The governing principle: every axis value a host declares must come from that
host's authoritative documentation. Where docs are silent, the host declares
the undocumented sentinel and the engine degrades fail-closed — it never
assumes a capability.
Protocol version
PROTOCOL_VERSION (a positive integer) is the interface version. It governs the
negotiated capability set; see the versioning policy
for what a bump means.
The nine negotiated axes
HOST_INTEGRATION_AXES is the closed vocabulary. Each axis takes a documented
value (or the undocumented sentinel):
| Axis | Values |
|---|---|
embeddingMode |
imperative | declarative |
commandSurface |
slash-file | slash-programmatic | slash-toml | palette | prose-only |
dispatch |
struct: { namedDispatch, nested, maxDepth, background, subagentToolkit, backgroundDispatch, isolation, maxConcurrency } |
modelMode |
active | passive |
hookBus |
host | engine | none |
stateIO |
filesystem | sandboxed-storage | session-log-append |
transport |
mcp | native-extension |
runtime |
node | bun | sandboxed-web | python | go | rust | electron | other |
effortSurface |
argv | none |
dispatch.isolation (harness-worktree | orchestrator-worktree | none, added #2584)
and dispatch.maxConcurrency (a positive integer, added #3673) are two dispatch
sub-fields with their own per-field fail-closed floors — unlike the other five
dispatch fields, they are not gated on namedDispatch. dispatch.maxConcurrency
degrades to 1 (strictly sequential) on anything other than a positive safe
integer (missing, the undocumented sentinel, zero, negative, fractional, an
unsafe integer, or a non-numeric type); there is no negotiated host/engine
reduction the way maxDepth has one — the resolved value passes through
unchanged. Its live transport (GSD_DISPATCH_MAX_CONCURRENCY) is read only at
the CLI query layer (gsd-tools query dispatch-capacity), never inside this
pure negotiation module, and takes precedence over the descriptor value, which
in turn takes precedence over the 1 fallback.
Classification + negotiation
profileOf(axes)→'programmatic-cli'|'declarative-cli'|'ide'|null.negotiateHostCapabilities(host, engine)→{ protocolVersion, effective, points, warnings }— the in-process negotiation. Pure; never throws.handleHandshakeRequest(request)/buildHandshakeRequest(descriptor)— the serialized (out-of-process) form of the same negotiation, JSON-safe across a wire boundary. The two are consistent: a serialized request yields the sameeffectiveaxes as the in-process call.degradationFor(point, axes)→{ level, fallback, unknown? }for one of the six interface points (command|dispatch|model|hooks|state|artifact).hookEventSurfaceFor(hookEvents)→ the host-fireable hook events for a dialect ('claude'|'gemini'|'opencode-subset'), ornullif unknown.shouldFlattenDispatch(dispatch)→truewhen the orchestrator must run inline (fail-closed).
The engine adapters
All five satisfy a common { kind, runtime, install, uninstall } shape and are
constructed fail-closed (they throw if a required host primitive is absent):
| Adapter | Factory | Selected by |
|---|---|---|
| Embedding (declarative) | createDeclarativeAdapter({runtime}) |
embeddingMode: 'declarative' |
| Embedding (imperative) | createImperativeAdapter({runtime}) |
embeddingMode: 'imperative' (also exposes the composed registry) |
| Model | createModelAdapter({modelMode}, {sendRequest?}) |
modelMode ('active' needs a host sendRequest) |
| Hook bus | createHookBus({bus}, {hostEmit?}) |
hookBus ('host' needs a host hostEmit) |
| State IO | createStateIO({io}, {backend?}) |
stateIO ('sandboxed-storage'/'session-log-append' need a host backend) |
The declarative + imperative adapters delegate install/uninstall in-process to
the same installRuntimeArtifacts engine function bin/install.js uses, so
adapter output is byte-identical to a first-party install (gated by the
differential attribution check, tests/emitted-attribution.test.cjs, ADR-2719).
Profiles
PROFILE_BASELINES fixes the three reference profiles:
| Profile | Baseline |
|---|---|
programmatic-cli |
imperative, slash-file, host bus, filesystem, mcp, node |
declarative-cli |
declarative, slash-file, host bus, filesystem, mcp, node |
ide |
imperative, palette, active model, engine bus, sandboxed-storage, sandboxed-web |
See also
- How-to: author a host-plugin
- Tutorial: embed GSD in a new host
- Interface versioning policy
- ADR-1239 (the design) ·
docs/reference/host-integration-capability-matrix.md(per-host values + citations)