* fix(#2615): document the effortSurface axis in the host-integration matrix #2481 added `effortSurface` as the ninth negotiated `hostIntegration` axis and wrote documentation-sourced values into 18 descriptors, but never touched `docs/reference/host-integration-capability-matrix.md`. The matrix that ADR-1239 designates the cited source of truth had zero occurrences of the axis: no entry in the axes legend, and no row in any of the per-runtime tables. `src/host-integration.cts` states "every value is documented or explicitly 'undocumented'" — for this axis that was false for every runtime. Adds the legend entry (the `argv` / `none` / `undocumented` vocabulary, plus why there is deliberately no config-file member) and an `effortSurface` row to all 19 per-runtime tables. Every citation is carried over from #2481's own commit message, where the values were sourced: - claude argv -- `claude --help` documents `--effort <level>` - opencode argv -- `opencode run --help` documents `--variant` - codex argv -- `model_reasoning_effort` is a config.toml key, not a dedicated flag, so the generic `-c key=value` override is the only argv route (still argv) - 15 hosts undocumented -- their docs state no reasoning setting kimi-code is the nineteenth section (added by #2603 after #2481) and is the one runtime with no declared value. Its row and a Documentation-gaps entry record why rather than inventing one: Kimi Code documents `/effort` (alias `/thinking`), but only as an INTERACTIVE slash command — `-m, --model` is the only model-adjacent argv. Neither vocabulary member is accurate (`none` would deny a mechanism the host has, `argv` would claim one it does not expose), so closing that gap needs a vocabulary decision, which is a negotiation change and not a documentation one. The absent value already degrades closed exactly as the sentinel does. The regression test derives its runtime list from the registry rather than hardcoding it, so a runtime added later fails until its matrix row exists — the ratchet whose absence let #2481 add an axis with nothing catching the missing docs. Closes #2615 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QT3ibz5qJuDuGqpTGRYVGf * docs(#2615): honest citations for the undocumented rows; fix the four stale 8-axis lists Two findings from the orthogonal review of the first commit. 1. The 15 `undocumented` rows shared byte-identical text — "searched the runtime's official docs (see Sources consulted above)" — which is weaker than this file's own convention ("no authoritative doc — searched: <url>") and, worse, implies a per-host targeted search that did not happen: each section's Sources-consulted list was gathered for OTHER axes and contains no CLI-reference or reasoning-effort source. The rows now say plainly what the finding is — an ABSENCE established by #2481's cross-host survey — and cite that survey rather than implying a URL was checked per host. 2. Four normative docs still described "the eight negotiated axes" and omitted effortSurface entirely. The worst of them is docs/how-to/add-or-update-a-host-integration.md — the maintainer's own guide for onboarding a host, whose Step 2 axis table would have a maintainer reproduce exactly the gap #2615 exists to close. Also fixed: docs/reference/host-integration-interface.md (which calls itself the normative reference and had no effortSurface row at all), docs/how-to/author-a-host-plugin.md, docs/registries/README.md ("**exactly** the eight … axes keys"), and CONTEXT.md's matching EoS-registry sentence. Deliberately NOT changed, because they are historical records rather than current contract: docs/whats-new-1.7.0.md and docs/FEATURES.md's 1.7.0 entry (effortSurface shipped in 1.8.0 via #2481 — rewriting them would falsify the release history), ADR-1239's pre-amendment body (already superseded by its own "Amendment (2026-07-21): effortSurface axis (#2481)"), and ADR-1016's "original eight axes", which refers to a different axis set entirely. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QT3ibz5qJuDuGqpTGRYVGf * chore(#2615): backfill changeset PR number (#2698) --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
4.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 } |
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 |
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
tests/golden-install-parity.test.cjs).
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)