Summary
ak x provider pick --host <subset> disables an excluded routing host only in kit.json (its flag flips to false). Everything the host left behind stays live:
- Seeded routes keep pointing at the disabled host.
providers.dualRouting entries (and their escalation rungs) naming the excluded host are retained verbatim and re-applied by applyAqeRouter into .agentic-qe/llm-config.json agentOverrides on every sync — aqe work keeps routing to a host the user just turned off.
- The codex MCP bridges stay registered.
mcp__codex__codex (project .mcp.json) and the ruflo server in codex's config.toml are marker-owned (providers.codexMcp / providers.rufloCodexMcp === 'ak'), but nothing runs the matching undoCodexMcp / undoRufloMcpInCodex on exclusion — the ensure* functions merely no-op once disabled, so both bridges linger indefinitely.
- Stale
agentOverrides on disk. applyAqeRouter merges {...existing.agentOverrides, ...projected} — entries ak projected for the excluded host are never pruned, even after the policy no longer names it.
Flagged by the cross-vendor (Codex) review on #67 (round 3, HIGH). Deliberately not fixed inside #67 to honor its maintainer-mandated scope; filed here as the follow-up.
Why now
#67 made the disable story asymmetric in a way users will feel: excluding opencode tears down surgically (marker-gated, priors restored, reported), while excluding codex silently leaves routes and bridges live. One command, two disable semantics — the same "two competing models" incoherence #67 was asked to eliminate for the adoption path. The capability-registry work in #71 will also need one teardown contract per host anyway; fixing this first gives it the codex reference implementation.
Proposed fix (sketch)
Treat routing-host exclusion in x provider pick the same as opencode exclusion — a disable, not just a flag flip:
- Bridge teardown (codex only): when codex goes enabled → excluded, run
undoCodexMcp({ managed: providers.codexMcp === 'ak' }) and undoRufloMcpInCodex({ managed: providers.rufloCodexMcp === 'ak' }), then null both markers and persist. Marker-gated, so user-registered servers survive — the exact opencode retireOpencode analog. (The bridges are codex's integration state: claude exclusion does not touch them, but see 2.)
- Policy prune (either routing host): drop
dualRouting entries whose host (or escalation hosts) name an excluded routing host — source: 'seeded' entries silently (ak-owned), source: 'user' entries with a per-entry warning (a pin pointing at a disabled host can only fail later).
- On-disk
agentOverrides prune: in applyAqeRouter, prune stale ak-curated keys: the projection key space is enumerable (AGENT_ACTIVITY_MAP), so on-disk entries inside that space but absent from the current projection are deleted; hand-added/foreign entries outside the space are preserved (merge-not-clobber still holds).
Out of scope for this issue: changing what x provider off does (it already tears down everything); any change to seeding, primary-host validation, or the routing defaults themselves.
Acceptance
References
Summary
ak x provider pick --host <subset>disables an excluded routing host only inkit.json(its flag flips tofalse). Everything the host left behind stays live:providers.dualRoutingentries (and their escalation rungs) naming the excluded host are retained verbatim and re-applied byapplyAqeRouterinto.agentic-qe/llm-config.jsonagentOverrideson every sync — aqe work keeps routing to a host the user just turned off.mcp__codex__codex(project.mcp.json) and therufloserver in codex'sconfig.tomlare marker-owned (providers.codexMcp/providers.rufloCodexMcp==='ak'), but nothing runs the matchingundoCodexMcp/undoRufloMcpInCodexon exclusion — theensure*functions merely no-op once disabled, so both bridges linger indefinitely.agentOverrideson disk.applyAqeRoutermerges{...existing.agentOverrides, ...projected}— entries ak projected for the excluded host are never pruned, even after the policy no longer names it.Flagged by the cross-vendor (Codex) review on #67 (round 3, HIGH). Deliberately not fixed inside #67 to honor its maintainer-mandated scope; filed here as the follow-up.
Why now
#67 made the disable story asymmetric in a way users will feel: excluding opencode tears down surgically (marker-gated, priors restored, reported), while excluding codex silently leaves routes and bridges live. One command, two disable semantics — the same "two competing models" incoherence #67 was asked to eliminate for the adoption path. The capability-registry work in #71 will also need one teardown contract per host anyway; fixing this first gives it the codex reference implementation.
Proposed fix (sketch)
Treat routing-host exclusion in
x provider pickthe same as opencode exclusion — a disable, not just a flag flip:undoCodexMcp({ managed: providers.codexMcp === 'ak' })andundoRufloMcpInCodex({ managed: providers.rufloCodexMcp === 'ak' }), then null both markers and persist. Marker-gated, so user-registered servers survive — the exact opencoderetireOpencodeanalog. (The bridges are codex's integration state: claude exclusion does not touch them, but see 2.)dualRoutingentries whosehost(or escalation hosts) name an excluded routing host —source: 'seeded'entries silently (ak-owned),source: 'user'entries with a per-entry warning (a pin pointing at a disabled host can only fail later).agentOverridesprune: inapplyAqeRouter, prune stale ak-curated keys: the projection key space is enumerable (AGENT_ACTIVITY_MAP), so on-disk entries inside that space but absent from the current projection are deleted; hand-added/foreign entries outside the space are preserved (merge-not-clobber still holds).Out of scope for this issue: changing what
x provider offdoes (it already tears down everything); any change to seeding, primary-host validation, or the routing defaults themselves.Acceptance
pick --host claudeon a codex-enabled machine: both codex MCP bridges removed (when ak-registered), markers nulled,dualRouting+agentOverridesname only claude afterwards, and a re-pick to codex re-wires cleanly.pick --host codexon a dual machine: routes naming claude pruned (user pins warned), bridges kept (they are codex's).docs/PROVIDERS.mddisable semantics describe one behavior for all hosts.References
src/commands/x/provider.mjs(pick),src/lib/providers.mjs(ensureCodexMcp/undoCodexMcp/ensureRufloMcpInCodex/undoRufloMcpInCodex,applyAqeRouter),src/lib/routing.mjs(AGENT_ACTIVITY_MAP).