Files
msd-core/docs/how-to/author-a-host-plugin.md
Tom Boucher 1008aabd31 fix(#2615): document the effortSurface axis in the host-integration matrix (#2698)
* 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>
2026-07-27 09:02:20 -04:00

3.4 KiB

How to author a host-plugin for GSD

This guide is for external tool authors who want to embed GSD's orchestration loop (dispatch + hooks + model + state) into a new host — a CLI, IDE, or agent runtime GSD does not special-case — by writing a host-plugin against the published Host-Integration SDK, without modifying gsd-core source.

The contract is the SDK entry (src/host-integration-sdk.cts → gsd-core/bin/lib/host-integration-sdk.cjs): import only from it. Everything it re-exports is public and versioned (PROTOCOL_VERSION); everything else in gsd-core is internal and may change. A smoke test (tests/sdk-smoke.test.cjs) proves a third-party host can be built from this surface alone.


1. Decide your host's profile

Classify your host into one of three profiles (the SDK's profileOf does this from your axes):

Profile Example hosts Binding
programmatic-cli OpenCode, pi imperative adapter (createImperativeAdapter)
declarative-cli Antigravity, Codex declarative adapter (createDeclarativeAdapter)
ide VS Code imperative adapter + engine-owned hook bus + active model + sandboxed state

2. Declare your host's integration axes

Declare the nine negotiated axes (embeddingMode, commandSurface, dispatch, modelMode, hookBus, stateIO, transport, runtime, effortSurface) from your host's authoritative documentation — never infer. Where the docs are silent, use the undocumented sentinel (the SDK degrades it fail-closed). See docs/reference/host-integration-interface.md for the closed vocabulary.

3. Compose the engine adapters

const SDK = require('@opengsd/gsd-core/sdk'); // the published entry

// Engine-owned hook bus (for hosts with no event bus, e.g. VS Code):
const hookBus = SDK.createHookBus({ bus: 'engine' });

// Active model via a host provider (e.g. vscode.lm); or 'passive' for CLIs:
const model = SDK.createModelAdapter({ modelMode: 'active' }, { sendRequest: hostSendRequest });

// State IO — filesystem for CLIs, sandboxed-storage for IDEs/web:
const stateIO = SDK.createStateIO({ io: 'filesystem' });

// The engine-as-library adapter bound to your runtime id:
const adapter = SDK.createImperativeAdapter({ runtime: 'my-host' });

4. Negotiate capabilities (serialized, for out-of-process hosts)

If your host runs out-of-process (can't share object refs with the engine), use the serialized handshake instead of the in-process negotiateHostCapabilities:

const req = SDK.buildHandshakeRequest({ ...myAxes });
const { effective, points, warnings } = SDK.handleHandshakeRequest(req);

The result is identical to the in-process negotiation for the same axes — that consistency is the contract.

5. Bind your host primitives + ship

Map the six interface points (command, dispatch, model, hooks, state, artifact) to your host's primitives (palette/chat, plugin API, provider calls, etc.). The reference host-plugins (OpenCode, Antigravity, pi, VS Code — see Phase 5) are canonical examples to mirror. Your host-plugin is now a self-contained artifact; no gsd-core source change is required.

See also

  • Tutorial: docs/tutorials/embed-gsd-in-a-new-host.md — a complete end-to-end embedding.
  • Reference: docs/reference/host-integration-interface.md — every axis, adapter, and the handshake.
  • Versioning: docs/explanation/interface-versioning-policy.md — what evolves additively vs. breaking.