deepseek-web-retrieval 0.5.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +21 -1
  2. package/README.md +167 -45
  3. package/dist/cli.js +2303 -1836
  4. package/docs/adr/0002-shared-config-base-layer.md +43 -0
  5. package/docs/agents/codex.md +60 -32
  6. package/docs/agents/opencode-v2.md +69 -39
  7. package/docs/agents/pi.md +60 -31
  8. package/docs/design/config-layering-design.md +180 -0
  9. package/docs/design/installer-design.md +33 -20
  10. package/docs/integration.md +41 -7
  11. package/docs/research/control-matrix.md +17 -4
  12. package/docs/research/mcp-compatibility.md +9 -2
  13. package/docs/research/ori-question-sourcing.md +336 -0
  14. package/docs/research/result-quality-passthrough.md +159 -0
  15. package/docs/research/search-api-defaults.md +18 -2
  16. package/docs/research/search-inline-content.md +244 -0
  17. package/examples/opencode.global.jsonc +3 -2
  18. package/package.json +2 -1
  19. package/src/core/auth.ts +3 -0
  20. package/src/core/client.ts +26 -4
  21. package/src/core/config-file.ts +168 -0
  22. package/src/core/config-summary.ts +82 -0
  23. package/src/core/constants.ts +15 -1
  24. package/src/core/descriptions.ts +6 -2
  25. package/src/core/env.ts +99 -32
  26. package/src/core/format.ts +19 -1
  27. package/src/core/options.ts +22 -2
  28. package/src/core/search.ts +6 -0
  29. package/src/core/types.ts +11 -0
  30. package/src/installer/apply.ts +5 -3
  31. package/src/installer/cli.ts +92 -25
  32. package/src/installer/config-command.ts +116 -0
  33. package/src/installer/hosts/codex.ts +5 -3
  34. package/src/installer/hosts/opencode.ts +9 -5
  35. package/src/installer/hosts/pi.ts +10 -6
  36. package/src/installer/ownership.ts +54 -1
  37. package/src/installer/paths.ts +7 -1
  38. package/src/installer/state.ts +73 -19
  39. package/src/installer/types.ts +12 -0
  40. package/src/mcp/auth.ts +2 -3
  41. package/src/mcp/cli.ts +9 -51
  42. package/src/mcp/serve.ts +60 -0
  43. package/src/mcp/server.ts +7 -2
  44. package/src/opencode/plugin.ts +22 -2
  45. package/src/pi/extension.ts +78 -9
  46. package/src/version.ts +12 -0
@@ -0,0 +1,180 @@
1
+ # Configuration layering design
2
+
3
+ Design note for the shared configuration base layer across the three shipped adapters (MCP
4
+ server, OpenCode plugin, Pi extension). It records the parameter taxonomy, the precedence
5
+ model, and the per-adapter composition so the design survives between conversations. Host
6
+ capability facts live in [control-matrix.md](../research/control-matrix.md); the config
7
+ surface inventory was verified against the code on 2026-10-23.
8
+
9
+ ## Problem
10
+
11
+ The state this design replaced — recorded here as history, not as the present. The option
12
+ pipeline was already single-sourced (names, defaults, clamping in
13
+ `src/core/constants.ts` → `src/core/env.ts` → `src/core/options.ts`), but the *channels*
14
+ that fed it were fragmented per host, and a multi-host user configured the same intent in
15
+ up to three ways:
16
+
17
+ - **Pi** — extension runs in-process; `DEEPSEEK_*` shell variables just worked.
18
+ - **Codex** — stdio children do not inherit the parent environment, and the installer's
19
+ `env_vars` entry forwarded **only** `DEEPSEEK_API_KEY`; every other knob set in the
20
+ shell never reached the server unless the user hand-edited `config.toml` to add each
21
+ variable name. (The entry now forwards every `DEEPSEEK_*` name — see the Codex
22
+ consequence in [ADR-0002](../adr/0002-shared-config-base-layer.md).)
23
+ - **OpenCode** — the plugin resolved **only** `ctx.options` (opencode.json plugin
24
+ options, camelCase); `DEEPSEEK_*` variables configured nothing there, so the same
25
+ knob had a second, differently-named vocabulary. (The plugin now composes
26
+ file < environment < `ctx.options` — see the per-adapter composition below.)
27
+
28
+ One intent ("20 results, block pinterest.com"), three configuration acts, two
29
+ vocabularies, one silent-failure trap. The isolation was accidental, not chosen.
30
+
31
+ ## Parameter taxonomy
32
+
33
+ Isolation versus unification is decided per class, not globally:
34
+
35
+ | Class | Parameters | Policy |
36
+ | --- | --- | --- |
37
+ | **API behavior** — describes the user↔DeepSeek relationship, host-independent | `count`, `maxResults`, `minRerank`, `minAuthority`, `allowUnknownAuthority`, `blockedDomains`, `includeDomains`, `language`, `searchLocalization`, `maxRetries`, `retryBaseDelayMs` | Shared base; identical everywhere unless a host layer overrides |
38
+ | **Host-sensitive** — interacts with host output caps / deadlines (OpenCode 2,000 lines / 50 KiB; Pi MCP 20 KB + 60 s; Pi extension uncapped; Claude Code 25k tokens) | `searchTimeoutMs`, `fetchTimeoutMs`, `fetchMaxChars`, `maxSummaryChars` | Shared base gives the safe default; **per-host override in the host-native layer is the recommended place** to raise them |
39
+ | **Host integration** — describes the host's tool landscape, not the API | `searchEnabled`, `fetchEnabled`, `setDefaultWebsearch`, `fetchOverrideWebfetch`, `fetchRegisterTool`, `apiKeySource` | **Deliberately isolated.** Installer-written, host-native config only; the shared file rejects them |
40
+
41
+ Security-shaped knobs (`fetchAllowedDomains`, `fetchBlockedDomains`, `fetchBlockPrivateHosts`)
42
+ are classed as API behavior: they are deployment policy about the DeepSeek call itself, and a
43
+ shared base strengthens rather than weakens them (one policy instead of three drifting ones).
44
+
45
+ ## The layering model
46
+
47
+ Precedence, low → high, identical semantics in every adapter:
48
+
49
+ ```
50
+ built-in defaults < shared config file < DEEPSEEK_* environment < host-native config
51
+ ```
52
+
53
+ - **Host-native config** means: OpenCode `ctx.options` (opencode.json plugin entry), Pi's
54
+ `deepseekWebRetrieval` settings namespace (the two switches), and — for MCP hosts — the
55
+ per-server `env` block in the host's MCP registration (that block is *how* an environment
56
+ variable arrives, not a fifth layer).
57
+ - Host-native layers keep outranking the base: installer-written intent (capability tiers)
58
+ and explicit per-host overrides always win, so the blast radius of a bad shared value is
59
+ bounded by whatever the host layer pins.
60
+ - The two vocabularies stay as they are — `DEEPSEEK_*` snake-case names for the environment,
61
+ camelCase `PluginOptions` keys for the file and OpenCode options — both generated from the
62
+ same single source and documented side by side.
63
+
64
+ ## The shared config file
65
+
66
+ - **Path:** `$XDG_CONFIG_HOME/deepseek-web-retrieval/config.json`, defaulting to
67
+ `~/.config/deepseek-web-retrieval/config.json`. On win32 an explicit, non-empty
68
+ `XDG_CONFIG_HOME` still wins; otherwise the conventional Roaming root applies —
69
+ `%APPDATA%\deepseek-web-retrieval\config.json`, falling back to
70
+ `<home>\AppData\Roaming\deepseek-web-retrieval\config.json` when `%APPDATA%` is
71
+ unset. User scope, one file. A project-scope file
72
+ is a confirmed non-goal for this iteration (open question below).
73
+ - **Format:** JSON object; keys are the camelCase `PluginOptions` vocabulary (class 1 and 2
74
+ only). Example:
75
+
76
+ ```json
77
+ {
78
+ "count": 20,
79
+ "blockedDomains": ["pinterest.com"],
80
+ "language": "zh",
81
+ "searchLocalization": "203.0.113.7"
82
+ }
83
+ ```
84
+
85
+ - **Validation:** the file's parsed object feeds the existing `resolvePluginOptions` —
86
+ clamps, IP validation, and domain normalization all come along for free. Unknown keys and
87
+ class-3 (host-integration) keys are **rejected with a one-line stderr warning** and
88
+ otherwise ignored; a missing or unparseable file contributes nothing (a warning line for
89
+ the unparseable case), mirroring the Pi settings reader's conventions.
90
+ - **The API key is deliberately absent.** Auth keeps its existing channels
91
+ (`DEEPSEEK_API_KEY`, OpenCode's auth store, Pi's env) — a config file is liable to end up
92
+ synced through dotfiles, and widening key storage is a security-surface decision this
93
+ design does not make.
94
+
95
+ ## Per-adapter composition
96
+
97
+ - **MCP server** (`src/mcp/serve.ts`): `resolveEnvOptions(env)` becomes
98
+ `resolveEnvOptions(env, readFileOptions())` — file keys under environment keys. The server
99
+ reads the file itself, so **the Codex `env_vars` trap disappears** regardless of what the
100
+ host forwards.
101
+ - **Pi extension** (`src/pi/extension.ts`): `resolveExtensionOptions` inserts the file
102
+ between defaults and the environment; the settings namespace stays on top, unchanged.
103
+ - **OpenCode plugin** (`src/opencode/plugin.ts`): `resolvePluginOptions(ctx.options)` becomes
104
+ `resolvePluginOptions({ ...fileOptions(), ...pluginOptionsFromEnv(process.env), ...ctx.options })`
105
+ — file, then environment, then the host layer. Additive only: existing opencode.json
106
+ options keep winning exactly as before; the change is that the file and environment now
107
+ work on this host too.
108
+
109
+ ## Installer changes
110
+
111
+ - **Codex `env_vars`:** enumerate **every** `DEEPSEEK_*` name (generated from
112
+ `src/core/constants.ts`, the single source) instead of only `DEEPSEEK_API_KEY`, so
113
+ environment overrides work on Codex without hand-editing `config.toml`. The note the
114
+ installer prints is updated to match.
115
+ - No other host artifacts change: the installer never writes the shared file (it is a user
116
+ authoring surface, like a shell profile), and capability tiers stay where they are.
117
+
118
+ ## Visibility
119
+
120
+ A bad shared value now fails everywhere at once, so effective configuration must be visible:
121
+
122
+ - The MCP server's startup stderr line (already printing the client identity and enabled
123
+ tools) additionally prints **deviations from defaults only** — e.g.
124
+ `config: count=20 blockedDomains=1 language=zh` — keeping the line short while showing
125
+ every non-default knob a multi-layer resolution produced.
126
+ - The OpenCode plugin and Pi extension print the same deviation summary once, at
127
+ registration time, through their host's logging channel (implementer picks the least
128
+ noisy channel per host; the content contract is "non-default effective values").
129
+ - `deepseek-web-retrieval config` is the user-facing arm: it prints every knob with its
130
+ value and source, replays the file's warnings where a human actually looks, and its
131
+ `--search` variant verifies the whole chain (key, config, network) with one billed
132
+ request.
133
+
134
+ ## What this design does not change
135
+
136
+ - `need_content` stays hardcoded `false` ([search-inline-content.md](../research/search-inline-content.md)).
137
+ - `ori_question` remains per-call-only (`original_question` input / Pi session fallback); it
138
+ is not configurable.
139
+ - Auth surfaces, capability tiers, and the installer's plan/confirm flow.
140
+
141
+ ## Testing
142
+
143
+ - Unit: file reader (missing / unparseable / unknown-key / class-3-key rejection with
144
+ warning), precedence matrix per adapter (defaults < file < env < host) asserted through
145
+ each adapter's existing resolution entry points.
146
+ - The installer's Codex plan snapshot gains the full `env_vars` list.
147
+ - Existing suites stay green; e2e scenarios unaffected (the file is absent in CI, which is
148
+ itself the empty-layer case).
149
+
150
+ ## Rollout
151
+
152
+ Additive and non-breaking: no existing configuration loses effect, no precedence between
153
+ existing layers changes. Documentation updates ship with the code: README gains a
154
+ "Configuration" section with the precedence table and the two-vocabulary table; the host
155
+ guides' option tables gain a shared-file column; the control-matrix note's Pi sentence
156
+ ("There is no per-extension options channel: the runtime config surface is the
157
+ `DEEPSEEK_*` environment") is updated to name the file as part of that surface.
158
+
159
+ **Amendment, 2026-10-23** — two changes approved after this design was confirmed alter
160
+ the effective behavior of *untouched* configurations, superseding the "no existing
161
+ configuration loses effect" sentence for those two knobs:
162
+
163
+ 1. `maxResults` now follows the effective `count` when unset, so `count`-only
164
+ configurations return `count` results instead of silently truncating to the old
165
+ default of 10 (the one-directional asymmetry is documented at the resolution site in
166
+ `src/core/options.ts`).
167
+ 2. Transient failures (408/425/429/5xx) retry twice by default instead of zero
168
+ (rationale and the dated vendor-survey correction live in
169
+ `docs/research/search-api-defaults.md`).
170
+
171
+ ## Decisions (confirmed 2026-10-23)
172
+
173
+ 1. **Project-scope file:** not in this iteration — hosts already own project-scope
174
+ semantics, and the extra precedence row is not yet earned by demand.
175
+ 2. **Invalid-key warnings:** one stderr line per bad key at first resolution — the noise
176
+ buys typo detection (`"retries"` vs `"maxRetries"`) in a hand-edited file.
177
+ 3. **File naming:** `config.json` inside the `~/.config/deepseek-web-retrieval/`
178
+ directory (win32: `%APPDATA%\deepseek-web-retrieval\`) — room for future siblings.
179
+ 4. **ADR:** the layering decision is recorded as
180
+ [ADR 0002](../adr/0002-shared-config-base-layer.md) alongside this design note.
@@ -6,6 +6,8 @@ Design note for the install-time flow, shipped as the `deepseek-web-retrieval in
6
6
  the design survives between conversations. Research backing lives in
7
7
  [control-matrix.md](../research/control-matrix.md); host facts in [hosts.jsonc](../hosts.jsonc).
8
8
  Remaining hosts get host modules here as their guides ship.
9
+ Examples involving other hosts describe design requirements for future modules;
10
+ the current CLI accepts only the three shipped hosts above.
9
11
 
10
12
  ## Principles
11
13
 
@@ -27,17 +29,16 @@ of the whole install.
27
29
  - **Optional** — registered, the model picks freely.
28
30
  - **Preferred** — registered plus rules steering the model toward them.
29
31
  - **Forced** — deterministic routing (replacement, exclusion, or de-facto).
30
- - **Off** — the capability's tool is not registered at all. When the other capability
31
- stays on, the MCP entry still lands and carries that capability's server-side
32
- false-only switch (`DEEPSEEK_ENABLE_SEARCH` / `DEEPSEEK_ENABLE_FETCH`); both off
33
- refuses to install anything.
32
+ - **Off** — the DeepSeek capability is hidden from the model through the adapter's
33
+ registration switch or Codex's host-side `disabled_tools` filter; the mapping below
34
+ describes each path. Both off refuses to install anything.
34
35
  - **Scope** — project-level (this checkout, shareable via VCS) or global (every project
35
36
  for that host on the machine).
36
37
 
37
38
  ## Stock configuration
38
39
 
39
40
  The tier definitions assume a clean host. Real installs land on configuration that
40
- already exists, and the installer runs three phases before anything is written:
41
+ already exists, and the installer uses three phases:
41
42
 
42
43
  1. **Detect.** Read the host config, the rules files, and the registered MCP servers.
43
44
  Report the conflict surface: existing rules steering toward another web tool; other
@@ -50,14 +51,15 @@ already exists, and the installer runs three phases before anything is written:
50
51
  which entries the installer appended; single-value keys (`websearch.provider`, Pi's
51
52
  `exposure`) snapshot the prior value before overwriting; files the installer creates
52
53
  are tracked as created. Nothing is written until the user approves the full plan.
53
- 3. **Verify.** After applying, confirm the chosen tier actually holds: the deny rules
54
- take effect, no higher layer overrides them, and the model sees exactly the intended
55
- tools.
54
+ 3. **Verify.** After applying, re-read the files and confirm the planned values and rules
55
+ were written. Runtime tool visibility and model routing are checked by host-specific
56
+ end-to-end scenarios, not by the installer itself.
56
57
 
57
58
  ## Tier semantics against stock configuration
58
59
 
59
- - **Optional is inherently stock-safe**: purely additive — it appends new entries
60
- without altering existing keys or values, and removes nothing. It is the safe default.
60
+ - **Optional keeps built-in routing unchanged**: it registers the DeepSeek capability
61
+ without preference rules or competitor exclusion. An existing DeepSeek registration
62
+ may still need replacement, which the plan shows and snapshots; inspect the preview.
61
63
  - **Preferred** can conflict without any config being touched: existing rules pointing
62
64
  at another web tool produce contradictory instructions whose outcome depends on each
63
65
  host's load order (Claude Code concatenates every level; Devin ranks team above
@@ -101,16 +103,17 @@ settings hierarchy, OpenCode's global versus project config) under three rules:
101
103
  alternative — the global fallback for a kill switch, or a different tier that works
102
104
  at project scope — instead of quietly writing to the other scope.
103
105
  - **Blast radius is part of the plan.** Global scope changes every project the user
104
- opens with that host; project scope is confined to one checkout but is often
105
- committed, which shares the config and rules with the whole team — including the
106
+ opens with that host; project scope normally writes into one checkout, while shared
107
+ config fallbacks such as Codex's retain user-wide effects. Project-local artifacts are
108
+ often committed, which shares the config and rules with the whole team — including the
106
109
  `${DEEPSEEK_API_KEY}` expansion that relies on each member's environment. The impact
107
110
  report states which applies.
108
111
  - **Layers above the user still outrank the choice.** Managed, enterprise, and system
109
112
  layers override anything the installer writes at either scope; the detect phase
110
113
  reports them instead of failing silently.
111
114
 
112
- Uninstall is scope-aware: removing a project-scope install never touches user-scope
113
- entries and vice versa, and a list mode shows what is installed where. The invariant is
115
+ Uninstall follows the files recorded for the chosen scope, including Codex's user-level
116
+ config even for a project-scope install; list shows those actual paths. The invariant is
114
117
  guarded, not just assumed: two records for one host never claim the same file. When a
115
118
  scope choice would overlap the other scope's record — Codex's project-scope fallback
116
119
  onto `~/.codex/config.toml` beside a global install — the plan refuses with guidance,
@@ -133,10 +136,13 @@ Do not delete an ownership sidecar while its install is still active.
133
136
 
134
137
  ## Rollback
135
138
 
136
- Uninstall reverses exactly what the plan applied: overwritten values restore their
137
- snapshots, merged arrays remove only the entries the installer appended, appended rules
138
- content is removed, and files the installer created are deleted — nothing more, nothing
139
- less. The [OpenCode v2 guide](../agents/opencode-v2.md) documents the failure mode this
139
+ Uninstall restores overwritten values from their snapshots only while the current value
140
+ still matches what the installer wrote; later user edits are kept and reported. Merged
141
+ arrays lose only matching entries the installer appended, and managed rules blocks are
142
+ removed while surrounding user content is retained. Installer-created config files are
143
+ deleted only when left empty; an empty rules file is also removed. TOML comments are not
144
+ restored because the codec reserializes the document. The
145
+ [OpenCode v2 guide](../agents/opencode-v2.md) documents the failure mode this
140
146
  avoids: `plugin remove` deletes the plugin entry but leaves `websearch.provider`
141
147
  pointing at the removed plugin, and the user must clean up by hand.
142
148
 
@@ -192,6 +198,14 @@ into any existing `permissions` array rather than replacing it.
192
198
  documents a layer above user config, so there is nothing to check there yet.
193
199
  - Only a bare `--apply` enables writes; assigning a value such as `--apply=false`
194
200
  is a usage error and writes nothing.
201
+ - `--pin` is opt-in version pinning: the ref written into host config gets the
202
+ running CLI's version appended (`name` becomes `name@<version>`; a ref already
203
+ ending in a version keeps it), so a host resolves that exact release instead of
204
+ the latest publish. Without the flag the ref stays unpinned, byte-identical to
205
+ before; re-running `init --pin` from a newer CLI moves the pin. Ref identity —
206
+ orphan, upgrade, and unexcludable-competitor detection — compares package names
207
+ with the `@version` suffix stripped (`samePackageName` in ownership.ts), so a
208
+ pinned ref still matches the lineage an earlier init registered.
195
209
  - File verification precedes the install-record commit. A write or verification
196
210
  failure restores the pre-apply files and record and checks the restored values.
197
211
  `ApplyError.status` is `rolled_back` only after recovery and new-claim cleanup
@@ -215,8 +229,7 @@ host module; their artifacts (from the tier-to-artifact mapping) remain hand-edi
215
229
  config until a module lands here. OpenCode's `opencode plugin add` remains available but
216
230
  cannot pass options or manage snapshots; `init` supersedes it for tiered installs.
217
231
 
218
-
219
- ### Persistence and concurrent operations
232
+ ## Persistence and concurrent operations
220
233
 
221
234
  Install records distinguish absent files from invalid or unreadable files. The
222
235
  reader validates version, host/scope identity, tiers, file metadata, and recorded
@@ -48,11 +48,11 @@ Codex are Apache-2.0; OpenCode and Pi are MIT. Claude Code and
48
48
  Cursor are proprietary. GitHub Copilot CLI and Devin CLI publish installers and docs, not
49
49
  source code, under proprietary terms.
50
50
 
51
- Support for the other popular CLI agents is in progress through the MCP server, which is
52
- shipped in `src/mcp/` and works with any host that supports MCP tools over stdio. A host is
53
- listed as supported only after an adapter and guide exist; for the remaining hosts,
54
- `No adapter yet` means the shipped MCP server already provides the path, but no guide for
55
- that host exists yet. All version locks live in [hosts.jsonc](hosts.jsonc), the single
51
+ OpenCode, Pi, and Codex have supported setup guides and installer host modules. The
52
+ MCP server in `src/mcp/` provides a possible stdio path for the remaining hosts, but
53
+ protocol compatibility alone does not establish a tested host setup. For those rows,
54
+ `No adapter yet` means no supported host-specific adapter or setup guide is shipped.
55
+ All version locks live in [hosts.jsonc](hosts.jsonc), the single
56
56
  source of truth for this table; OpenCode is pinned to the adapter's tested target, not
57
57
  necessarily the latest OpenCode release. Control tiers per host and capability — optional,
58
58
  preferred, or forced routing — are researched in [control-matrix.md](research/control-matrix.md),
@@ -63,7 +63,7 @@ whose per-host reference also carries MCP registration and rules files.
63
63
  One line per host. The [per-host reference](research/control-matrix.md#per-host-reference) carries
64
64
  the details: built-in web tools and their kill switches, MCP registration, and rules files.
65
65
 
66
- - **OpenCode v2** — The only shipped adapter. It uses OpenCode's native plugin API and
66
+ - **OpenCode v2** — Uses OpenCode's native plugin API and
67
67
  exposes both a websearch provider and a fetch tool/override. See
68
68
  [OpenCode v2](agents/opencode-v2.md).
69
69
  - **Claude Code** — Ships built-in `WebSearch` and `WebFetch` tools. See
@@ -82,7 +82,41 @@ the details: built-in web tools and their kill switches, MCP registration, and r
82
82
  the native extension adapter (the recommended path), with the MCP server as the fallback;
83
83
  see [Pi](agents/pi.md) and [Pi in the per-host reference](research/control-matrix.md#pi).
84
84
 
85
- ## Roadmap
85
+ ## Upgrading existing installs
86
+
87
+ For an installation managed by `init`:
88
+
89
+ 1. Run `npx deepseek-web-retrieval@latest list` from the original project directory,
90
+ using the same home and `XDG_CONFIG_HOME` as the original installation.
91
+ 2. Run `npx deepseek-web-retrieval@latest init` with the original `--host`, `--scope`,
92
+ `--search`, and `--fetch` values, changing only the settings you intend to change.
93
+ Review the plan and repeat with `--apply`; re-init preserves the original snapshots
94
+ needed for uninstall. A global install can still claim shared configuration from a
95
+ particular project, so keep the original working directory for upgrades.
96
+ 3. Refresh the package in the host and start or reload a session as described in its
97
+ guide. For Pi's extension path, use `pi update --extensions`. To pin the host's
98
+ package to the exact version being run, pass `--pin` to init (it writes
99
+ `deepseek-web-retrieval@X.Y.Z` into the registration); upgrading a pinned install
100
+ means re-running init with the newer CLI, since updating the CLI alone does not
101
+ move an independently pinned host package. `--package` still overrides the ref
102
+ entirely.
103
+
104
+ When upgrading from 0.4.0, Pi's default changes from MCP to the native extension.
105
+ Pass `--path mcp` explicitly to retain MCP, or `--path extension` to migrate; the plan
106
+ shows the old path's removals and retains the original uninstall snapshots. OpenCode's
107
+ native plugin and Codex's MCP path remain the same. Standalone MCP installs no longer
108
+ require OpenCode or Pi SDKs; native adapters use the SDKs provided by their hosts.
109
+
110
+ Keep install records and ownership sidecars: deleting them loses recovery information
111
+ and can cause a later init to refuse an existing registration. If an operation was
112
+ interrupted, follow the [recovery guidance](design/installer-design.md#persistence-and-concurrent-operations)
113
+ before retrying. For manual installations, update the package reference or checkout and
114
+ follow the host guide rather than adopting the config through init.
115
+
116
+ Code importing the core's removed `formatFetchContent` helper must migrate to
117
+ `formatFetchedContent`, which returns both `content` and `truncated`.
118
+
119
+ ## Available paths and future hosts
86
120
 
87
121
  - **MCP server** — shipped in `src/mcp/` (the fallback path in the [Pi](agents/pi.md) guide
88
122
  and the path in the [Codex](agents/codex.md) guide); the broadest route for hosts that
@@ -118,7 +118,11 @@ paths imply the available scopes; keys locked to a single scope are enumerated i
118
118
  ([rmcp_client.rs at rust-v0.163.0](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/codex-mcp/src/rmcp_client.rs));
119
119
  `enabled_tools`/`disabled_tools` (verbatim raw tool-name match, filtered before
120
120
  registration so the model never sees a disabled tool; an empty `enabled_tools` allow-list
121
- exposes nothing), per-tool approval modes, and output limits.
121
+ exposes nothing), per-tool approval modes, and output limits: MCP tool output can be
122
+ capped per tool via `output_token_limit` ("Token budget for one MCP tool's output,
123
+ before the standard 20% serialization allowance"; the default cap is not published
124
+ there)
125
+ ([mcp_types.rs at rust-v0.163.0](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/config/src/mcp_types.rs)).
122
126
  stdio children do not inherit the parent environment (only `HOME`, `PATH`, and explicit
123
127
  `env`), so `DEEPSEEK_API_KEY` must be passed explicitly. When a tool result has
124
128
  `structuredContent`, Codex replaces the content blocks with the serialized JSON. No SSE.
@@ -146,6 +150,13 @@ paths imply the available scopes; keys locked to a single scope are enumerated i
146
150
  tool from model requests entirely; `webfetch` has no disable config key at 2.0.32 — the
147
151
  deterministic paths are a permissions deny (`action: "webfetch"`) or a plugin
148
152
  tool-transform removal, the latter being what `fetchOverrideWebfetch` does.
153
+ - **Tool output caps** — plugin tool results truncate at 2,000 lines / 50 KiB: every
154
+ tool result passes through `ToolOutput.truncate` (`MAX_LINES = 2000`,
155
+ `MAX_BYTES = 50 KiB`), with the full output retained to a `tool-output/` file for
156
+ 7 days
157
+ ([tool-output.ts at v2.0.32](https://github.com/anomalyco/opencode/blob/v2.0.32/packages/core/src/tool-output.ts));
158
+ caps and model-channel behavior recorded in
159
+ [result-quality-passthrough.md](result-quality-passthrough.md).
149
160
  - **MCP registration** — out of scope for this host: the shipped path is the plugin
150
161
  adapter, and OpenCode's MCP support is not part of it.
151
162
  - **Rules** — `AGENTS.md` only (no CLAUDE.md fallback in v2): global
@@ -170,7 +181,9 @@ paths imply the available scopes; keys locked to a single scope are enumerated i
170
181
  `process.env` (no forwarding), and results bypass the MCP layer entirely, so neither the
171
182
  20 KB truncation nor the 60 s request timeout applies. There is no per-extension options
172
183
  channel: the runtime config surface is the `DEEPSEEK_*` environment (the same pipeline as
173
- the MCP server) plus a `deepseekWebRetrieval` settings namespace the installer writes for
184
+ the MCP server), the shared config file
185
+ (`~/.config/deepseek-web-retrieval/config.json`, layered under the environment), plus a
186
+ `deepseekWebRetrieval` settings namespace the installer writes for
174
187
  the off tier — Pi preserves unknown settings keys on read and on its own rewrites
175
188
  (`pi install`), verified at 1.3.0. Action methods such as `getSettings()` cannot be
176
189
  called during extension loading, so the adapter reads the settings files itself.
@@ -181,8 +194,8 @@ paths imply the available scopes; keys locked to a single scope are enumerated i
181
194
  prerequisite for every tier. SSE is rejected. Text results over 20 KB are
182
195
  middle-truncated with the full text saved to a file, and the per-request default
183
196
  timeout is 60 s. Pi is content-first for the model, with a `structuredContent`
184
- fallback used only when a result has no content blocks — the one open-source host that
185
- touches `structuredContent` at all — and a re-declared (not validated) tool
197
+ fallback used only when a result has no content blocks, unlike Codex's preference for
198
+ `structuredContent`, and a re-declared (not validated) tool
186
199
  `outputSchema`.
187
200
  - **Rules** — `AGENTS.md`/`CLAUDE.md` context files from the agent dir, the working
188
201
  directory, and its parents; `SYSTEM.md` replaces the system prompt and `APPEND_SYSTEM.md`
@@ -117,7 +117,10 @@ differences:
117
117
  content-first, falling back to `structuredContent` only when a result has no content
118
118
  blocks (verified in `tools.ts` at v1.3.0). No `outputSchema` is declared: the SDK
119
119
  rejects text-only results for a tool with a declared schema, and no host in the
120
- matrix validates the schema anyway.
120
+ matrix validates the schema anyway. The per-host model-channel facts behind this —
121
+ which of `content`/`structuredContent` provably reaches the model on each host,
122
+ native adapter paths included — are recorded in
123
+ [result-quality-passthrough.md](result-quality-passthrough.md).
121
124
  2. **stdio is the universal transport.** Every host in the matrix launches stdio servers
122
125
  with the same conceptual JSON (`mcpServers` → `command`/`args`/`env`), differing only in
123
126
  file location and cosmetic field names. stdio needs no OAuth and no URL config, and the
@@ -129,7 +132,7 @@ differences:
129
132
  1.0.81+). A v1.x-built server still works today — modern clients fall back to the legacy
130
133
  handshake — but it can never offer the stateless era; v2 serves both from one entry
131
134
  point.
132
- 4. **Streamable HTTP only for a hosted deployment.** All nine hosts support it (with
135
+ 4. **Streamable HTTP only for a hosted deployment.** All seven MCP hosts surveyed here support it (with
133
136
  different `type` strings: `http`, `streamable-http`, `streamableHttp`), and OAuth 2.1
134
137
  resource-server behavior (RFC 9728 metadata) then applies; prefer pre-registered clients
135
138
  over the now-deprecated Dynamic Client Registration.
@@ -139,6 +142,10 @@ differences:
139
142
  truncation, environment passing, output caps, and per-host approval surfaces; consult
140
143
  it per host rather than this summary.
141
144
 
145
+ These protocol findings describe compatibility at the research baseline, not completed
146
+ end-to-end support for every host. The shipped server exposes stdio; supported setup
147
+ guides and installer coverage are listed in the [integration model](../integration.md).
148
+
142
149
  ## Sources
143
150
 
144
151
  ### Specification and SDKs