@kontextmind/kxm 0.7.185 → 0.7.186
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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.kxm/README.md +1 -1
- package/.kxm/roles/writer.yaml +1 -1
- package/CHANGELOG.md +9 -0
- package/docs/contributing/assignment-runner.md +2 -2
- package/docs/contributing/ci-and-release.md +1 -1
- package/docs/contributing/harness-routing-internals.md +12 -12
- package/docs/glossary.md +1 -1
- package/docs/guides/governed-skills.md +1 -1
- package/docs/guides/pi-workers.md +2 -2
- package/docs/guides/provenance-gates.md +1 -1
- package/docs/operations/troubleshooting.md +1 -1
- package/docs/reference/cli-reference.md +11 -11
- package/docs/reference/config-reference.md +10 -10
- package/docs/reference/configuration.md +2 -2
- package/docs/reference/harness-routing.md +12 -12
- package/package.json +1 -1
- package/packages/core/tui/dist/index.js +1 -1
- package/packages/core/tui/src/tui/optimizer.ts +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +16 -12
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/runtime-supervisor.js +6 -2
- package/plugins/kxm/dist/runtime.js +7 -3
- package/plugins/kxm/dist/server.js +0 -1
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/cli/system.ts +1 -1
- package/plugins/kxm/src/init-guide-setup.ts +9 -9
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/oneshot-producer.ts +2 -2
- package/plugins/kxm/src/pi-producer.ts +1 -1
- package/plugins/kxm/src/subagent-control.ts +1 -1
- package/plugins/kxm/src/workforce-names.mjs +12 -4
- package/scripts/harness-run.d.mts +1 -1
- package/scripts/harness-run.mjs +2 -2
package/.kxm/README.md
CHANGED
|
@@ -37,7 +37,7 @@ Ids in this checkout follow one convention per kind:
|
|
|
37
37
|
|---|---|---|
|
|
38
38
|
| Role | The purpose: `planner`, `writer`, `reviewer-arch`, `reviewer-cli` | Unchanged |
|
|
39
39
|
| Agent | The same id as its `role` | `planner`, `writer`, `reviewer-arch`, `reviewer-cli` |
|
|
40
|
-
| Route | `<harness>-<model-slug>[-<provider>]`, with `.` written as `-` | `grok-grok-4-7`, `claude-fable`, `pi-qwen3-
|
|
40
|
+
| Route | `<harness>-<model-slug>[-<provider>]`, with `.` written as `-` | `grok-grok-4-7`, `claude-fable`, `pi-qwen3-7-plus-openrouter` |
|
|
41
41
|
| Workflow | `default`, `land`, or `<role>-only` | `default`, `land`, `writer-only`, `reviewer-arch-only`, `reviewer-cli-only` |
|
|
42
42
|
| Agent step | The agent's role id | `writer`, `reviewer-arch`, `reviewer-cli` |
|
|
43
43
|
|
package/.kxm/roles/writer.yaml
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -216,6 +216,15 @@ All notable user-facing changes are documented here. The project follows [Semant
|
|
|
216
216
|
|
|
217
217
|
### Changed
|
|
218
218
|
|
|
219
|
+
- **Writer #2 is OpenRouter Qwen3.7 Plus.** `pi-qwen3-7-plus-openrouter`
|
|
220
|
+
(`openrouter/qwen/qwen3.7-plus`) replaces `pi-qwen3-coder-plus-openrouter`.
|
|
221
|
+
OpenRouter no longer lists `qwen/qwen3-coder-plus`. The live catalog on
|
|
222
|
+
2026-10-17 prices Qwen3.7 Plus at $0.32 input and $1.28 output per 1M
|
|
223
|
+
tokens, with a 1,000,000-token context and tool support. The old model
|
|
224
|
+
file stays `status: retired`, off every roster, and `qwen-openrouter-pi`
|
|
225
|
+
no longer resolves. `.kxm/prices.yaml` keeps the last Coder Plus row and
|
|
226
|
+
adds the Qwen3.7 Plus base tier. The dev helper's only Pi writer is
|
|
227
|
+
`openrouter/qwen/qwen3.7-plus`.
|
|
219
228
|
- **The CLI critic is Codex GPT-6.1 Sol.** `codex-gpt-6-1-sol` is the
|
|
220
229
|
`reviewer-cli` primary (`codex` / `gpt-6.1-sol`, effort `low`).
|
|
221
230
|
`pi-qwen3-8-flash-openrouter` stays the other-vendor fallback, and
|
|
@@ -34,7 +34,7 @@ admits each route for specific roles and permissions:
|
|
|
34
34
|
|
|
35
35
|
| Role | Admitted route (harness / model) | Vendor | Permission |
|
|
36
36
|
|---|---|---|---|
|
|
37
|
-
| `writer` | `grok` / `grok-4.7`; relief: `pi` / `openrouter/qwen/qwen3-
|
|
37
|
+
| `writer` | `grok` / `grok-4.7`; relief: `pi` / `openrouter/qwen/qwen3.7-plus`; `agy` / `gemini-4-argon-high`, then `gemini-4-argon-medium`, then `gemini-3.8-flash-medium`, then `gemini-3.8-flash-high` | `xai`; `alibaba`; `google` | `edit` |
|
|
38
38
|
| `planner` | `claude` / `fable` | `anthropic` | `read-only` |
|
|
39
39
|
| `reviewer-arch` | `claude` / `fable` | `anthropic` | `read-only` |
|
|
40
40
|
| `reviewer-cli` | `codex` / `gpt-6.1-sol`; fallback `pi` / `openrouter/qwen/qwen3.8-flash`, then `codex` / `gpt-5.6-sol` | `openai`; `alibaba`; `openai` | `read-only` |
|
|
@@ -347,7 +347,7 @@ and exits with status 2. It refuses when:
|
|
|
347
347
|
segment must not be a braked native vendor (`x-ai`, `moonshotai` and
|
|
348
348
|
`google-ai` count as `xai`, `moonshot` and `google`);
|
|
349
349
|
- a Pi `edit` request comes from a role other than `experiment` or `writer`, or
|
|
350
|
-
a Pi writer asks for anything but `openrouter/qwen/qwen3-
|
|
350
|
+
a Pi writer asks for anything but `openrouter/qwen/qwen3.7-plus` with
|
|
351
351
|
`edit`;
|
|
352
352
|
- the request asks for hooks or skills, sets `max_cost_usd` for a harness other
|
|
353
353
|
than Claude, or sets `max_turns` for a harness other than Grok;
|
|
@@ -269,7 +269,7 @@ The real Pi smoke calls paid models, so it never runs by default. Its workflow,
|
|
|
269
269
|
`KXM_SMOKE_RUNNER` names a runner with Pi credentials. Both smoke models run as
|
|
270
270
|
long-lived Pi workers, so each must pass the Pi native-vendor brake: pick two
|
|
271
271
|
non-native routes such as
|
|
272
|
-
`openrouter/qwen/qwen3-
|
|
272
|
+
`openrouter/qwen/qwen3.7-plus,openrouter/z-ai/glm-5.3-flash`, never `xai/…`
|
|
273
273
|
or `anthropic/…`. The container smoke needs
|
|
274
274
|
Docker, a `pass-cli` session and a local Pi model store. It keeps secrets in a
|
|
275
275
|
mode-600 file inside a temporary directory; set `KXM_SMOKE_VAULT` to read keys
|
|
@@ -9,7 +9,7 @@ This page records how the KXM repository applies [harness routing](../reference/
|
|
|
9
9
|
|
|
10
10
|
The files use one id shape per kind. A route id is `<harness>-<model-slug>[-<provider>]`, with `.` written as `-`. An agent id equals its role. A workflow id is `default`, `land`, or `<role>-only`. An agent step id equals that role.
|
|
11
11
|
|
|
12
|
-
This checkout's routes are `grok-grok-4-7`, `pi-qwen3-
|
|
12
|
+
This checkout's admitted routes are `grok-grok-4-7`, `pi-qwen3-7-plus-openrouter`, `agy-gemini-4-argon-high`, `agy-gemini-4-argon-medium`, `agy-gemini-3-8-flash-medium`, `agy-gemini-3-8-flash-high`, `claude-fable`, `codex-gpt-6-1-sol`, `codex-gpt-5-6-sol`, `pi-qwen3-8-flash-openrouter`, and `pi-glm-5-3-flash-openrouter`. `pi-qwen3-coder-plus-openrouter` stays on disk with `status: retired` because OpenRouter removed `qwen/qwen3-coder-plus` (catalog 404); it is not admitted and not on a roster, and `qwen-openrouter-pi` does not resolve. Agents are `planner`, `writer`, `reviewer-arch`, and `reviewer-cli`. `opus-claude` was removed because `opus` is not an admitted selector. `qwen-token-plan/*` and `zai-coding-cn/*` left the admitted list because those harnesses are not allowlisted; their `prices.yaml` rows stay. Other old ids resolve as aliases. Every roster entry names an effort. `reviewer-arch` dispatches `claude-fable`. #343's architecture critic ran on opus because the justfile recipe review-arch hardcoded that model; the role file on that commit listed only `fable-claude`. The helper now refuses `opus`.
|
|
13
13
|
|
|
14
14
|
## This checkout's routes and roster
|
|
15
15
|
|
|
@@ -25,7 +25,7 @@ skills: []
|
|
|
25
25
|
roster:
|
|
26
26
|
- route: grok-grok-4-7
|
|
27
27
|
effort: medium
|
|
28
|
-
- route: pi-qwen3-
|
|
28
|
+
- route: pi-qwen3-7-plus-openrouter
|
|
29
29
|
effort: medium
|
|
30
30
|
- route: agy-gemini-4-argon-high
|
|
31
31
|
effort: medium
|
|
@@ -37,7 +37,7 @@ roster:
|
|
|
37
37
|
effort: medium
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
The writer role lists route ids, in order: `grok-grok-4-7`, then `pi-qwen3-
|
|
40
|
+
The writer role lists route ids, in order: `grok-grok-4-7`, then `pi-qwen3-7-plus-openrouter`, then `agy-gemini-4-argon-high`, `agy-gemini-4-argon-medium`, `agy-gemini-3-8-flash-medium`, and `agy-gemini-3-8-flash-high`. `grok-grok-4-7` is harness `grok`, model `grok-4.7`, vendor `xai`. An agent file does not declare `harness:`. Argon is writer #3 and #4. Flash medium is the safety net because Argon needs a paid Google AI Pro, Ultra, or Enterprise plan and `agy -p` exits when the pinned model is missing. Flash high stays on the roster so that admitted model file is still used. The planner primary stays `claude-fable`. The CLI critic primary is `codex-gpt-6-1-sol`, then `pi-qwen3-8-flash-openrouter`, then `codex-gpt-5-6-sol`. The architecture critic primary stays `claude-fable`, then `pi-glm-5-3-flash-openrouter`. Argon can serve as a planner or architecture-review fallback; it is not on those rosters. GPT-6.1 Sol Pro is the same model with reasoning mode `pro`. The route id does not carry a reasoning mode, role effort has no `pro` value, and codex is limited to `reviewer-cli`, so that mode is not an architecture fallback.
|
|
41
41
|
|
|
42
42
|
`node scripts/kxm.mjs routes list`:
|
|
43
43
|
|
|
@@ -49,7 +49,7 @@ admitted google/gemini-4-argon-high
|
|
|
49
49
|
admitted google/gemini-4-argon-medium
|
|
50
50
|
admitted openai/gpt-5.6-sol
|
|
51
51
|
admitted openai/gpt-6.1-sol
|
|
52
|
-
admitted openrouter/qwen/qwen3-
|
|
52
|
+
admitted openrouter/qwen/qwen3.7-plus
|
|
53
53
|
admitted openrouter/qwen/qwen3.8-flash
|
|
54
54
|
admitted openrouter/z-ai/glm-5.3-flash
|
|
55
55
|
admitted xai/grok-4.7
|
|
@@ -61,14 +61,14 @@ reviewer-cli codex-gpt-6-1-sol
|
|
|
61
61
|
reviewer-cli pi-qwen3-8-flash-openrouter
|
|
62
62
|
reviewer-cli codex-gpt-5-6-sol
|
|
63
63
|
writer grok-grok-4-7
|
|
64
|
-
writer pi-qwen3-
|
|
64
|
+
writer pi-qwen3-7-plus-openrouter
|
|
65
65
|
writer agy-gemini-4-argon-high
|
|
66
66
|
writer agy-gemini-4-argon-medium
|
|
67
67
|
writer agy-gemini-3-8-flash-medium
|
|
68
68
|
writer agy-gemini-3-8-flash-high
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
-
`routes admit --model openrouter/qwen/qwen3-
|
|
71
|
+
`routes admit --model openrouter/qwen/qwen3.7-plus --dry-run` exits 2 with `select a model from the refreshed inventory` even though that selector is already admitted, because the inventory never carries `openrouter/…` selectors. Selectors like these are admitted by a Git-reviewed edit of `.kxm/routes.yaml`.
|
|
72
72
|
|
|
73
73
|
On the capture machine, `kxm harness list` showed `claude` detected but logged out (`dispatch no (not_authenticated)`), `deepseek` not installed, and `grok`, `codex`, `kimi` and `agy` ready.
|
|
74
74
|
|
|
@@ -85,9 +85,9 @@ The issue-127 runner (`kxm assign`, see the [assignment runner](assignment-runne
|
|
|
85
85
|
harness: grok
|
|
86
86
|
model: grok-4.7
|
|
87
87
|
vendor: xai
|
|
88
|
-
pi-qwen3-
|
|
88
|
+
pi-qwen3-7-plus-openrouter:
|
|
89
89
|
harness: pi
|
|
90
|
-
model: openrouter/qwen/qwen3-
|
|
90
|
+
model: openrouter/qwen/qwen3.7-plus
|
|
91
91
|
vendor: alibaba
|
|
92
92
|
```
|
|
93
93
|
|
|
@@ -108,7 +108,7 @@ The product layers are in [What the brake refuses](../reference/harness-routing.
|
|
|
108
108
|
|
|
109
109
|
| Layer | Where | What it refuses | What you see |
|
|
110
110
|
|---|---|---|---|
|
|
111
|
-
| Dev helper | `scripts/harness-run.mjs` | A braked Pi provider, a Pi provider outside the allowlist, a Pi writer other than `openrouter/qwen/qwen3-
|
|
111
|
+
| Dev helper | `scripts/harness-run.mjs` | A braked Pi provider, a Pi provider outside the allowlist, a Pi writer other than `openrouter/qwen/qwen3.7-plus`, or an aggregator id whose vendor segment is a native vendor | `pi brake: xai has a native harness; refusing Pi impersonation`, or `… refusing to bill it through openrouter` |
|
|
112
112
|
| Developer roster | `scripts/roster-policy.mjs` | An aggregator route whose vendor segment is a native vendor | `Roster policy refused: native vendor cannot use Pi` |
|
|
113
113
|
|
|
114
114
|
The dev helper's allowlist (`openrouter`, `nous-portal`, `antigravity`) is a different list from `PI_ALLOWED_PROVIDERS` in `plugins/kxm/src/harness.ts`, which gates nothing. Which of the two should govern is an open decision (Tracking → Still open). Edit permission exists only in the dev helper, and only for admitted writer or experiment routes. The helper accepts only a ChatGPT login for codex, not an API key.
|
|
@@ -129,7 +129,7 @@ These extend the generic examples on the reference page with this checkout's adm
|
|
|
129
129
|
| Billing | grok.com subscription (OAuth) | $2.00 input, $6.00 output, $0.50 cached input |
|
|
130
130
|
| Context | 500,000 (`x-ai/grok-4.7` in the refreshed inventory) | 500,000 |
|
|
131
131
|
|
|
132
|
-
Pi's own `xai` provider reported `ready` (OAuth) on the capture machine. When the grok quota runs out, the next writer in the lineup is `pi-qwen3-
|
|
132
|
+
Pi's own `xai` provider reported `ready` (OAuth) on the capture machine. When the grok quota runs out, the next writer in the lineup is `pi-qwen3-7-plus-openrouter`, a different vendor.
|
|
133
133
|
|
|
134
134
|
### GPT-6.1 Sol
|
|
135
135
|
|
|
@@ -177,11 +177,11 @@ The code differs from that decision: `.kxm/routes.yaml` admits `google/gemini-3.
|
|
|
177
177
|
| Model | Vendor-plan route | OpenRouter route | Notes |
|
|
178
178
|
|---|---|---|---|
|
|
179
179
|
| Qwen3.8 Flash | `qwen-token-plan/qwen3.8-flash`: removed from the admitted list on 2026-09-27; `qwen-token-plan` is not allowlisted | `openrouter/qwen/qwen3.8-flash`: admitted, route `pi-qwen3-8-flash-openrouter`, read-only fallback for planner and reviewer-cli | `prices.yaml` keeps both rows. |
|
|
180
|
-
| Qwen3
|
|
180
|
+
| Qwen3.7 Plus | none | `openrouter/qwen/qwen3.7-plus`: route `pi-qwen3-7-plus-openrouter`, writer #2 | The only admitted Pi writer: exact model, `edit` permission. OpenRouter list on 2026-10-17 is $0.32 input and $1.28 output per 1M tokens, 1,000,000 context, tools supported. |
|
|
181
181
|
| GLM 5.3 and 5.3 Flash | `zai-coding-cn/glm-5.3` and `…/glm-5.3-flash`: removed from the admitted list on 2026-09-27; `zai-coding-cn` is not allowlisted | `openrouter/z-ai/glm-5.3-flash`: admitted, route `pi-glm-5-3-flash-openrouter`, read-only fallback for reviewer-arch | Z.ai has no native harness. |
|
|
182
182
|
| DeepSeek V4.1 Flash | `qwen-token-plan/deepseek-v4.1-flash`: removed from the admitted list on 2026-09-27 | `deepseek/deepseek-v4.1-flash` in the OpenRouter feed | Bills a DeepSeek model through Alibaba's plan. `deepseek` is a native-vendor Pi brake, so this is not a route. |
|
|
183
183
|
|
|
184
|
-
The developer runner is stricter. Its only Pi writer is `openrouter/qwen/qwen3-
|
|
184
|
+
The developer runner is stricter. Its only Pi writer is `openrouter/qwen/qwen3.7-plus`, and it does not allowlist `qwen-token-plan` or `zai-coding-cn`. Today OpenRouter is the right answer here for Qwen3.7 Plus, Qwen3.8 Flash and GLM 5.3 Flash. `qwen/qwen3-coder-plus` is retired.
|
|
185
185
|
|
|
186
186
|
### Nous
|
|
187
187
|
|
package/docs/glossary.md
CHANGED
|
@@ -427,7 +427,7 @@ A list of allowed models. It means either a [role](#role)'s roster, or the devel
|
|
|
427
427
|
|
|
428
428
|
### Route
|
|
429
429
|
|
|
430
|
-
A model selector, such as `xai/grok-4.6` or `openrouter/qwen/qwen3-
|
|
430
|
+
A model selector, such as `xai/grok-4.6` or `openrouter/qwen/qwen3.7-plus`, that a step can run on. The harness that runs it comes from the agent or the project default. See [Harness routing](reference/harness-routing.md).
|
|
431
431
|
|
|
432
432
|
### Session
|
|
433
433
|
|
|
@@ -61,7 +61,7 @@ Write the procedure as a Markdown file. KXM adds `name` and `description` front
|
|
|
61
61
|
```bash
|
|
62
62
|
kxm skills create --file flaky.md --name "Triage flaky test" \
|
|
63
63
|
--description "Isolate and classify a flaky test before changing code" \
|
|
64
|
-
--created-by agent-a --harness pi --models openrouter/qwen/qwen3-
|
|
64
|
+
--created-by agent-a --harness pi --models openrouter/qwen/qwen3.7-plus \
|
|
65
65
|
--journal journal_abc
|
|
66
66
|
```
|
|
67
67
|
|
|
@@ -82,7 +82,7 @@ When no unused fallback remains, the worker waits `KXM_WORKER_PROVIDER_RETRY_MS`
|
|
|
82
82
|
> [!IMPORTANT]
|
|
83
83
|
> A worker refuses to start on a model whose vendor has its own native harness. Before Pi starts, the worker runs `--model` and every `--fallback-models` entry through the Pi native-vendor brake, and exits 1 with `pi_native_impersonation_blocked` on the first one it refuses: a native provider (`xai/…`), that vendor's own Pi provider (`openai-codex/…`, `kimi-coding/…`), or an aggregator path to it (`openrouter/x-ai/…`). `--dry-run` does not run this check.
|
|
84
84
|
|
|
85
|
-
Pick every model with [Harness routing](../reference/harness-routing.md), for example `openrouter/qwen/qwen3-
|
|
85
|
+
Pick every model with [Harness routing](../reference/harness-routing.md), for example `openrouter/qwen/qwen3.7-plus` with the fallback `openrouter/z-ai/glm-5.3-flash`. The brake cannot check a worker started without `--model`, which runs Pi's default model, or a bare model id that lets Pi choose the provider, so name the provider.
|
|
86
86
|
|
|
87
87
|
An agent name is only a label. To use a native-harness model as a peer, connect that harness to the hub under the agent name instead, for example the Claude Code plugin with the name `reviewer-claude`.
|
|
88
88
|
|
|
@@ -203,7 +203,7 @@ kxm hub stop
|
|
|
203
203
|
| `KXM worker <project>/<name> is already managed by PID <pid>` | A supervisor for this agent is already running. | Use the running worker, or stop it first. |
|
|
204
204
|
| The worker exits with `worker requires --name and --project` | Name or project missing. | Pass `--name` and `--project`, or set `KXM_AGENT_NAME` and `KXM_PROJECT`. |
|
|
205
205
|
| `KXM_WORKER_FALLBACK_MODELS requires KXM_WORKER_MODEL` | Fallbacks without a primary model. | Add `--model`. |
|
|
206
|
-
| The worker exits 1 with `pi_native_impersonation_blocked: …` | `--model` or a fallback is a model whose vendor has its own harness. | Run that model in its native harness, or use an admitted Pi route such as `openrouter/qwen/qwen3-
|
|
206
|
+
| The worker exits 1 with `pi_native_impersonation_blocked: …` | `--model` or a fallback is a model whose vendor has its own harness. | Run that model in its native harness, or use an admitted Pi route such as `openrouter/qwen/qwen3.7-plus`. |
|
|
207
207
|
| `kxm connection failed` in the Pi log, or Pi shows `hub:off` | Wrong URL, token, or project, or the name is live elsewhere (`duplicate_agent_name`). | Compare `KXM_SERVER_URL`, `KXM_AUTH_TOKEN`, and `KXM_PROJECT` with the hub; check `kxm peer list`. |
|
|
208
208
|
| Workflow runs share one conversation | Isolation is `off`, the default. | Restart with `--session-isolation workflow`. |
|
|
209
209
|
| A request stays `delivered` | A turn, tool, or provider call is still running, or the watchdogs are recovering it. | Read the lifecycle log. Do not send a duplicate. |
|
|
@@ -173,7 +173,7 @@ kxm agent worker --name reviewer-grok --project provenance-demo --model <reviewe
|
|
|
173
173
|
</details>
|
|
174
174
|
|
|
175
175
|
> [!IMPORTANT]
|
|
176
|
-
> The reviewer names are labels. Choose every Pi model with [Harness routing](../reference/harness-routing.md), for example `openrouter/qwen/qwen3-
|
|
176
|
+
> The reviewer names are labels. Choose every Pi model with [Harness routing](../reference/harness-routing.md), for example `openrouter/qwen/qwen3.7-plus` and `openrouter/z-ai/glm-5.3-flash` for two reviewers from different vendors. A worker refuses a model whose vendor has its own native harness, such as Anthropic or xAI, with `pi_native_impersonation_blocked`. To use such a model as a reviewer, connect its native harness under the same agent name instead, for example the Claude Code plugin as `reviewer-claude`.
|
|
177
177
|
|
|
178
178
|
In an operator terminal, supply the workflow-start secret, validate the definition, and create a run:
|
|
179
179
|
|
|
@@ -134,7 +134,7 @@ The [plugin troubleshooting guide](../../plugins/kxm/README.md#troubleshooting)
|
|
|
134
134
|
| The heartbeat is healthy but one tool never finishes | A tool exceeded `KXM_WORKER_TOOL_TIMEOUT_MS` (31 minutes by default, above the 30-minute fanout wait) | The worker logs `worker_tool_timeout` and restarts the child; raise the limit only above the longest legitimate call |
|
|
135
135
|
| A long-lived worker keeps restarting | Pi is missing from the service `PATH`, the working directory is gone, or model credentials are missing | Read `worker_process_error` and `worker_exited`; set `KXM_PI_COMMAND` to an explicit path |
|
|
136
136
|
| A read-only reviewer edits files | Prompt wording does not remove tools | Set `KXM_WORKER_TOOLS=read,grep,find,ls` |
|
|
137
|
-
| The worker exits at once with `pi_native_impersonation_blocked` | `--model` or a `--fallback-models` entry is a model whose vendor has its own harness, such as `xai/…`, `openai-codex/…` or `openrouter/x-ai/…` | Run that model in its native harness, or pick an admitted Pi route such as `openrouter/qwen/qwen3-
|
|
137
|
+
| The worker exits at once with `pi_native_impersonation_blocked` | `--model` or a `--fallback-models` entry is a model whose vendor has its own harness, such as `xai/…`, `openai-codex/…` or `openrouter/x-ai/…` | Run that model in its native harness, or pick an admitted Pi route such as `openrouter/qwen/qwen3.7-plus`; see [Harness routing](../reference/harness-routing.md#what-the-brake-refuses) |
|
|
138
138
|
|
|
139
139
|
Use `--fresh-start`, not `--no-continue`, when only the first launch must avoid old session state.
|
|
140
140
|
|
|
@@ -1157,7 +1157,7 @@ admitted google/gemini-4-argon-high
|
|
|
1157
1157
|
admitted google/gemini-4-argon-medium
|
|
1158
1158
|
admitted openai/gpt-5.6-sol
|
|
1159
1159
|
admitted openai/gpt-6.1-sol
|
|
1160
|
-
admitted openrouter/qwen/qwen3-
|
|
1160
|
+
admitted openrouter/qwen/qwen3.7-plus
|
|
1161
1161
|
admitted openrouter/qwen/qwen3.8-flash
|
|
1162
1162
|
admitted openrouter/z-ai/glm-5.3-flash
|
|
1163
1163
|
admitted xai/grok-4.7
|
|
@@ -1169,7 +1169,7 @@ reviewer-cli codex-gpt-6-1-sol
|
|
|
1169
1169
|
reviewer-cli pi-qwen3-8-flash-openrouter
|
|
1170
1170
|
reviewer-cli codex-gpt-5-6-sol
|
|
1171
1171
|
writer grok-grok-4-7
|
|
1172
|
-
writer pi-qwen3-
|
|
1172
|
+
writer pi-qwen3-7-plus-openrouter
|
|
1173
1173
|
writer agy-gemini-4-argon-high
|
|
1174
1174
|
writer agy-gemini-4-argon-medium
|
|
1175
1175
|
writer agy-gemini-3-8-flash-medium
|
|
@@ -1181,7 +1181,7 @@ kxm routes list --json
|
|
|
1181
1181
|
```
|
|
1182
1182
|
|
|
1183
1183
|
```text
|
|
1184
|
-
{"schema":"kxm.cli-result.v1","ok":true,"command":"routes list","policy":{"schema":"kxm.routes.v2","updatedAt":"2026-10-17T14:30:00.000Z","admitted":["anthropic/fable","google/gemini-3.8-flash-high","google/gemini-3.8-flash-medium","google/gemini-4-argon-high","google/gemini-4-argon-medium","openai/gpt-5.6-sol","openai/gpt-6.1-sol","openrouter/qwen/qwen3-
|
|
1184
|
+
{"schema":"kxm.cli-result.v1","ok":true,"command":"routes list","policy":{"schema":"kxm.routes.v2","updatedAt":"2026-10-17T14:30:00.000Z","admitted":["anthropic/fable","google/gemini-3.8-flash-high","google/gemini-3.8-flash-medium","google/gemini-4-argon-high","google/gemini-4-argon-medium","openai/gpt-5.6-sol","openai/gpt-6.1-sol","openrouter/qwen/qwen3.7-plus","openrouter/qwen/qwen3.8-flash","openrouter/z-ai/glm-5.3-flash","xai/grok-4.7"],"disabled":[]},"membership":["planner claude-fable","planner pi-qwen3-8-flash-openrouter","reviewer-arch claude-fable","reviewer-arch pi-glm-5-3-flash-openrouter","reviewer-cli codex-gpt-6-1-sol","reviewer-cli pi-qwen3-8-flash-openrouter","reviewer-cli codex-gpt-5-6-sol","writer grok-grok-4-7","writer pi-qwen3-7-plus-openrouter","writer agy-gemini-4-argon-high","writer agy-gemini-4-argon-medium","writer agy-gemini-3-8-flash-medium","writer agy-gemini-3-8-flash-high"]}
|
|
1185
1185
|
```
|
|
1186
1186
|
|
|
1187
1187
|
### `kxm routes count`
|
|
@@ -1386,7 +1386,7 @@ kxm role get writer --json
|
|
|
1386
1386
|
```
|
|
1387
1387
|
|
|
1388
1388
|
```text
|
|
1389
|
-
{"schema":"kxm.cli-result.v1","ok":true,"command":"role get","roleId":"writer","scope":"local","filePath":"/work/kxm/.kxm/roles/writer.yaml","role":{"schema":"kxm.role.v2","id":"writer","purpose":"writer","permission":"edit","description":"Primary implementation agent.","skills":[],"roster":[{"route":"grok-grok-4-7","effort":"medium"},{"route":"pi-qwen3-
|
|
1389
|
+
{"schema":"kxm.cli-result.v1","ok":true,"command":"role get","roleId":"writer","scope":"local","filePath":"/work/kxm/.kxm/roles/writer.yaml","role":{"schema":"kxm.role.v2","id":"writer","purpose":"writer","permission":"edit","description":"Primary implementation agent.","skills":[],"roster":[{"route":"grok-grok-4-7","effort":"medium"},{"route":"pi-qwen3-7-plus-openrouter","effort":"medium"},{"route":"agy-gemini-4-argon-high","effort":"medium"},{"route":"agy-gemini-4-argon-medium","effort":"medium"},{"route":"agy-gemini-3-8-flash-medium","effort":"medium"},{"route":"agy-gemini-3-8-flash-high","effort":"medium"}]}}
|
|
1390
1390
|
```
|
|
1391
1391
|
|
|
1392
1392
|
Captured from this checkout with `node scripts/kxm.mjs role get writer --json`. The path is shortened to `/work/kxm`.
|
|
@@ -1396,7 +1396,7 @@ kxm role modify writer --add-skill kxm --dry-run --json
|
|
|
1396
1396
|
```
|
|
1397
1397
|
|
|
1398
1398
|
```text
|
|
1399
|
-
{"schema":"kxm.cli-result.v1","ok":true,"command":"role modify","roleId":"writer","id":"writer","role":{"schema":"kxm.role.v2","id":"writer","purpose":"writer","permission":"edit","description":"Primary implementation agent.","skills":["kxm"],"roster":[{"route":"grok-grok-4-7","effort":"medium"},{"route":"pi-qwen3-
|
|
1399
|
+
{"schema":"kxm.cli-result.v1","ok":true,"command":"role modify","roleId":"writer","id":"writer","role":{"schema":"kxm.role.v2","id":"writer","purpose":"writer","permission":"edit","description":"Primary implementation agent.","skills":["kxm"],"roster":[{"route":"grok-grok-4-7","effort":"medium"},{"route":"pi-qwen3-7-plus-openrouter","effort":"medium"},{"route":"agy-gemini-4-argon-high","effort":"medium"},{"route":"agy-gemini-4-argon-medium","effort":"medium"},{"route":"agy-gemini-3-8-flash-medium","effort":"medium"},{"route":"agy-gemini-3-8-flash-high","effort":"medium"}]},"filePath":"/work/kxm/.kxm/roles/writer.yaml","scope":"local","dryRun":true,"planned":[{"action":"write","target":"/work/kxm/.kxm/roles/writer.yaml"}]}
|
|
1400
1400
|
```
|
|
1401
1401
|
|
|
1402
1402
|
Add an existing route to a role's roster (Not run):
|
|
@@ -2014,11 +2014,11 @@ Starts a long-lived, supervised Pi RPC worker in the foreground through `scripts
|
|
|
2014
2014
|
- Needs Pi and a reachable hub. Runs until stopped (`kxm hub stop` stops managed workers too). The exit code is the worker's.
|
|
2015
2015
|
- A name and project are required (exit 2 otherwise); an invalid isolation mode exits 2.
|
|
2016
2016
|
- `--dry-run` prints a `kxm.worker-result.v1` envelope with `workspace`, `name`, `project`, `model`, `fallbackModels`, `tools`, `sessionIsolation`, `continue`, `freshStart`.
|
|
2017
|
-
- Before Pi starts, the worker runs `--model` and every `--fallback-models` entry through the Pi native-vendor brake. A model whose vendor has its own harness (for example `xai/…`, `openai-codex/…`, `openrouter/x-ai/…` or `antigravity/claude-…`) exits 1 with `pi_native_impersonation_blocked: <message>` on stderr; use the native harness, or an admitted Pi route such as `openrouter/qwen/qwen3-
|
|
2017
|
+
- Before Pi starts, the worker runs `--model` and every `--fallback-models` entry through the Pi native-vendor brake. A model whose vendor has its own harness (for example `xai/…`, `openai-codex/…`, `openrouter/x-ai/…` or `antigravity/claude-…`) exits 1 with `pi_native_impersonation_blocked: <message>` on stderr; use the native harness, or an admitted Pi route such as `openrouter/qwen/qwen3.7-plus`. `--dry-run` does not run this check. See [Harness routing](harness-routing.md#what-the-brake-refuses).
|
|
2018
2018
|
- The remaining worker variables are described in [Long-lived worker settings](configuration.md#long-lived-worker-settings).
|
|
2019
2019
|
|
|
2020
2020
|
```bash
|
|
2021
|
-
kxm agent worker --name reviewer --project demo --model openrouter/qwen/qwen3-
|
|
2021
|
+
kxm agent worker --name reviewer --project demo --model openrouter/qwen/qwen3.7-plus --tools read,grep,find,ls --session-isolation workflow --fresh-start --dry-run
|
|
2022
2022
|
```
|
|
2023
2023
|
|
|
2024
2024
|
```text
|
|
@@ -2026,7 +2026,7 @@ would start worker
|
|
|
2026
2026
|
```
|
|
2027
2027
|
|
|
2028
2028
|
```bash
|
|
2029
|
-
kxm agent worker --name coordinator --project demo --model openrouter/qwen/qwen3-
|
|
2029
|
+
kxm agent worker --name coordinator --project demo --model openrouter/qwen/qwen3.7-plus --session-isolation workflow
|
|
2030
2030
|
```
|
|
2031
2031
|
|
|
2032
2032
|
Not run: starts a long-lived Pi worker.
|
|
@@ -3362,7 +3362,7 @@ Submit a skill candidate from verified episodes.
|
|
|
3362
3362
|
- Writes a candidate. Honors `--dry-run`. JSON keys: `metadata` (or `name` for a dry run).
|
|
3363
3363
|
|
|
3364
3364
|
```bash
|
|
3365
|
-
kxm skills create --file SKILL.md --name retry-backoff --created-by alice --harness pi --models openrouter/qwen/qwen3-
|
|
3365
|
+
kxm skills create --file SKILL.md --name retry-backoff --created-by alice --harness pi --models openrouter/qwen/qwen3.7-plus --run wf_123 --dry-run --json
|
|
3366
3366
|
```
|
|
3367
3367
|
|
|
3368
3368
|
```text
|
|
@@ -3627,7 +3627,7 @@ Dedicated offline benchmark for side-by-side model comparison (Decision Q12). To
|
|
|
3627
3627
|
| Option | Argument | Default | Description |
|
|
3628
3628
|
|---|---|---|---|
|
|
3629
3629
|
| `--task` | `<fixture>` | `Deterministic benchmark task` | Task prompt or fixture path for benchmark comparison |
|
|
3630
|
-
| `--arms` | `<models>` | `grok/grok-4.6,claude/fable,pi/qwen3-
|
|
3630
|
+
| `--arms` | `<models>` | `grok/grok-4.6,claude/fable,pi/qwen3.7-plus` | Comma-separated model routes to benchmark (e.g. grok/grok-4.6,claude/fable) |
|
|
3631
3631
|
| `--runs` | `<count>` | `1` | Benchmark runs per arm |
|
|
3632
3632
|
|
|
3633
3633
|
- Reads nothing. JSON keys: `task`, `runs`, `timestamp`, `arms` (`harness`, `model`, `latencyMs`, `tokensIn`, `tokensOut`, `costUsd`, `outcome`).
|
|
@@ -3641,7 +3641,7 @@ Routing Benchmark Results (task: Deterministic benchmark task, runs: 1)
|
|
|
3641
3641
|
Harness Model Latency(ms) TokensIn TokensOut Cost($) Outcome
|
|
3642
3642
|
grok grok-4.6 420 1200 450 $0.17 passed
|
|
3643
3643
|
claude fable 680 1200 450 $0.45 passed
|
|
3644
|
-
pi qwen3-
|
|
3644
|
+
pi qwen3.7-plus 560 1200 450 $0.12 passed
|
|
3645
3645
|
```
|
|
3646
3646
|
|
|
3647
3647
|
## `kxm prices`
|
|
@@ -963,7 +963,7 @@ description: Primary implementation agent.
|
|
|
963
963
|
roster:
|
|
964
964
|
- route: grok-grok-4-7
|
|
965
965
|
effort: medium
|
|
966
|
-
- route: pi-qwen3-
|
|
966
|
+
- route: pi-qwen3-7-plus-openrouter
|
|
967
967
|
effort: medium
|
|
968
968
|
```
|
|
969
969
|
|
|
@@ -991,7 +991,7 @@ unknown keys are ignored).
|
|
|
991
991
|
|
|
992
992
|
A route string is derived from the selected model file's `vendor` and
|
|
993
993
|
`model`, joined by a slash: `xai/grok-4.6`, `anthropic/fable`,
|
|
994
|
-
`openrouter/qwen/qwen3-
|
|
994
|
+
`openrouter/qwen/qwen3.7-plus`. When the file is missing, nothing is
|
|
995
995
|
admitted and every live attempt is refused (`producer_route_unsupported`, or
|
|
996
996
|
`producer_route_not_admitted` from the live producer). A leftover
|
|
997
997
|
`.kxm/producers.yaml` makes every reader fail with `retired
|
|
@@ -1002,7 +1002,7 @@ admitted and every live attempt is refused (`producer_route_unsupported`, or
|
|
|
1002
1002
|
`model_selection_required`. Inventory IDs come in several shapes (bare
|
|
1003
1003
|
`grok-4.6` from `grok models`, `vendor/model` from OpenRouter,
|
|
1004
1004
|
`provider/model` from `pi --list-models`), so a route such as
|
|
1005
|
-
`openrouter/qwen/qwen3-
|
|
1005
|
+
`openrouter/qwen/qwen3.7-plus` or `anthropic/fable` usually has to be
|
|
1006
1006
|
added by editing the file.
|
|
1007
1007
|
|
|
1008
1008
|
```yaml
|
|
@@ -1013,7 +1013,7 @@ admitted:
|
|
|
1013
1013
|
- openai/gpt-5.6-sol
|
|
1014
1014
|
- openai/gpt-6.1-sol
|
|
1015
1015
|
- xai/grok-4.6
|
|
1016
|
-
- openrouter/qwen/qwen3-
|
|
1016
|
+
- openrouter/qwen/qwen3.7-plus
|
|
1017
1017
|
disabled: []
|
|
1018
1018
|
```
|
|
1019
1019
|
|
|
@@ -1068,9 +1068,9 @@ routes:
|
|
|
1068
1068
|
roles: [writer]
|
|
1069
1069
|
permissions: [edit]
|
|
1070
1070
|
status: admitted # admitted | retired
|
|
1071
|
-
pi-qwen3-
|
|
1071
|
+
pi-qwen3-7-plus-openrouter:
|
|
1072
1072
|
harness: pi
|
|
1073
|
-
model: openrouter/qwen/qwen3-
|
|
1073
|
+
model: openrouter/qwen/qwen3.7-plus # Pi: allowed provider prefix + vendor/model
|
|
1074
1074
|
vendor: alibaba
|
|
1075
1075
|
roles: [writer]
|
|
1076
1076
|
permissions: [edit]
|
|
@@ -1097,7 +1097,7 @@ routes:
|
|
|
1097
1097
|
permissions: [read-only]
|
|
1098
1098
|
status: admitted
|
|
1099
1099
|
lineup: # routes admitted for each role, preference order
|
|
1100
|
-
writer: [grok-grok-4-7, pi-qwen3-
|
|
1100
|
+
writer: [grok-grok-4-7, pi-qwen3-7-plus-openrouter, agy-gemini-4-argon-high, agy-gemini-4-argon-medium, agy-gemini-3-8-flash-medium, agy-gemini-3-8-flash-high]
|
|
1101
1101
|
planner: [claude-fable, pi-qwen3-8-flash-openrouter]
|
|
1102
1102
|
reviewer-arch: [claude-fable, pi-glm-5-3-flash-openrouter]
|
|
1103
1103
|
reviewer-cli: [codex-gpt-6-1-sol, pi-qwen3-8-flash-openrouter, codex-gpt-5-6-sol]
|
|
@@ -1105,11 +1105,11 @@ required_critics:
|
|
|
1105
1105
|
review-arch: claude-fable
|
|
1106
1106
|
review-cli: codex-gpt-6-1-sol
|
|
1107
1107
|
model_origins: # required for every Pi route model
|
|
1108
|
-
openrouter/qwen/qwen3-
|
|
1108
|
+
openrouter/qwen/qwen3.7-plus:
|
|
1109
1109
|
vendor: alibaba
|
|
1110
1110
|
evidence:
|
|
1111
|
-
source: plans/evidence/route-
|
|
1112
|
-
sha256:
|
|
1111
|
+
source: plans/evidence/route-pi-qwen3-7-plus-openrouter.md
|
|
1112
|
+
sha256: 10e11cfa572ef4891e514d229fa8b7f0f355b31e6481315a6dd763bbe44244a1
|
|
1113
1113
|
```
|
|
1114
1114
|
|
|
1115
1115
|
Validated with `validateRosterDocument` from `scripts/roster-policy.mjs`,
|
|
@@ -166,14 +166,14 @@ For example, a review-only worker that cannot edit the checkout:
|
|
|
166
166
|
|
|
167
167
|
```bash
|
|
168
168
|
export KXM_WORKER_TOOLS="read,grep,find,ls,kxm_list,kxm_get,kxm_reply"
|
|
169
|
-
kxm agent worker --name reviewer --project <project> --model openrouter/qwen/qwen3-
|
|
169
|
+
kxm agent worker --name reviewer --project <project> --model openrouter/qwen/qwen3.7-plus
|
|
170
170
|
```
|
|
171
171
|
|
|
172
172
|
<details><summary>PowerShell</summary>
|
|
173
173
|
|
|
174
174
|
```powershell
|
|
175
175
|
$env:KXM_WORKER_TOOLS = "read,grep,find,ls,kxm_list,kxm_get,kxm_reply"
|
|
176
|
-
kxm agent worker --name reviewer --project <project> --model openrouter/qwen/qwen3-
|
|
176
|
+
kxm agent worker --name reviewer --project <project> --model openrouter/qwen/qwen3.7-plus
|
|
177
177
|
```
|
|
178
178
|
|
|
179
179
|
</details>
|
|
@@ -12,11 +12,11 @@ These are KXM's routing rules. The code enforces them in layers: the Pi native-v
|
|
|
12
12
|
- **Same model, prefer the subscription.** Prefer an authenticated native subscription for the same model.
|
|
13
13
|
- **Quota exhaustion is not a license to cross-bill.** Take the **next best** authenticated option by quality, then cost, from the report, not a silent Pi API key for the same vendor.
|
|
14
14
|
- **A harness is not a model, and it is not a worker.** A harness runs only the models it hosts. Only Pi is a long-lived worker. `grok` and `agy` are one-shot CLIs.
|
|
15
|
-
- **Admission is a decision, not a config tweak.** A route that is not admitted is refused. Admit one precise selector, such as `openrouter/qwen/qwen3-
|
|
15
|
+
- **Admission is a decision, not a config tweak.** A route that is not admitted is refused. Admit one precise selector, such as `openrouter/qwen/qwen3.7-plus`, never a whole provider.
|
|
16
16
|
|
|
17
17
|
## 1. Decision procedure: "I want model X"
|
|
18
18
|
|
|
19
|
-
1. **Name the vendor of X.** The vendor is the lab that trained the model, not whoever bills you for it. `x-ai/grok-4.6` is xAI. `qwen/qwen3-
|
|
19
|
+
1. **Name the vendor of X.** The vendor is the lab that trained the model, not whoever bills you for it. `x-ai/grok-4.6` is xAI. `qwen/qwen3.7-plus` is Alibaba. `z-ai/glm-5.3` is Z.ai.
|
|
20
20
|
2. **Check whether the vendor has a native harness.** KXM maps `anthropic→claude`, `openai→codex`, `xai→grok`, `google→agy`, `moonshot→kimi` and `deepseek→deepseek`. Google is an exception (section 4). If the vendor is not in this list, go to step 6.
|
|
21
21
|
3. **Check that the native harness is installed and logged in.** In `kxm harness list`, the row must show `detected yes`, `auth yes` and `dispatch yes`. `no` and `unknown` are never eligible.
|
|
22
22
|
4. **Check that the harness hosts X.** `claude` runs only Anthropic models. `grok` runs only `grok-*`. `agy` runs only `gemini-*`. `kimi` runs only `kimi-*` or `moonshot-*`. `deepseek` runs only `deepseek-*`. `codex` refuses other vendors' model prefixes. To see the exact ids, use the harness's own catalog: `grok models`, `agy models` or `kimi provider list`.
|
|
@@ -92,14 +92,14 @@ codex login status
|
|
|
92
92
|
grok models
|
|
93
93
|
agy models
|
|
94
94
|
kimi provider list
|
|
95
|
-
pi auth check --model openrouter/qwen/qwen3-
|
|
95
|
+
pi auth check --model openrouter/qwen/qwen3.7-plus --json --no-refresh
|
|
96
96
|
```
|
|
97
97
|
|
|
98
98
|
## 2. Which route will a config line use?
|
|
99
99
|
|
|
100
100
|
### How KXM builds a route
|
|
101
101
|
|
|
102
|
-
- **Selector.** The selector is `<vendor>/<model>` from the selected `.kxm/models/<route>.yaml`. The agent names a `role`, `.kxm/roles/<role>.yaml` lists route ids, and the chosen roster entry names that model file. The model id may contain `/`, for example `openrouter/qwen/qwen3-
|
|
102
|
+
- **Selector.** The selector is `<vendor>/<model>` from the selected `.kxm/models/<route>.yaml`. The agent names a `role`, `.kxm/roles/<role>.yaml` lists route ids, and the chosen roster entry names that model file. The model id may contain `/`, for example `openrouter/qwen/qwen3.7-plus`.
|
|
103
103
|
- **Harness.** The harness is the `harness` field on that model file. An agent file does not select it.
|
|
104
104
|
- **Admission.** The selector must be admitted. The engine uses the first roster entry whose model file is readable and whose route is admitted.
|
|
105
105
|
- **Dispatch probe.** Before spawning anything, the producer probes the exact harness, provider and model triple. It refuses unhosted pairs and the Pi brake.
|
|
@@ -135,7 +135,7 @@ model: openrouter/x-ai/grok-4.7
|
|
|
135
135
|
vendor: xai
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
-
The selector is `openrouter/x-ai/grok-4.7` and the harness is `pi`. The Pi brake refuses it before Pi starts, because the vendor segment `x-ai` is xAI, which has a native harness. A vendor with no native harness runs in the same shape: with `model: openrouter/qwen/qwen3-
|
|
138
|
+
The selector is `openrouter/x-ai/grok-4.7` and the harness is `pi`. The Pi brake refuses it before Pi starts, because the vendor segment `x-ai` is xAI, which has a native harness. A vendor with no native harness runs in the same shape: with `model: openrouter/qwen/qwen3.7-plus`, Pi is spawned with `--model openrouter/qwen/qwen3.7-plus`, its read-only flags (section 3) and `-p --mode json`. Write `model` exactly as the provider names it. For OpenRouter that is the vendor slug, so `x-ai`, not `xai`.
|
|
139
139
|
|
|
140
140
|
The harness and the selector have to agree. Pi refuses `provider: xai` and `openrouter/x-ai/…`. `grok` refuses `provider: openrouter`. [What the brake refuses](#what-the-brake-refuses) has the exact messages.
|
|
141
141
|
|
|
@@ -153,7 +153,7 @@ description: Primary implementation agent.
|
|
|
153
153
|
roster:
|
|
154
154
|
- route: grok-grok-4-7
|
|
155
155
|
effort: medium
|
|
156
|
-
- route: pi-qwen3-
|
|
156
|
+
- route: pi-qwen3-7-plus-openrouter
|
|
157
157
|
effort: medium
|
|
158
158
|
- route: agy-gemini-4-argon-high
|
|
159
159
|
effort: medium
|
|
@@ -165,7 +165,7 @@ roster:
|
|
|
165
165
|
effort: medium
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
-
`grok-grok-4-7` resolves to `.kxm/models/grok-grok-4-7.yaml`: harness `grok`, model `grok-4.7`, vendor `xai`, status `admitted`, permission `edit`. `pi-qwen3-
|
|
168
|
+
`grok-grok-4-7` resolves to `.kxm/models/grok-grok-4-7.yaml`: harness `grok`, model `grok-4.7`, vendor `xai`, status `admitted`, permission `edit`. `pi-qwen3-7-plus-openrouter` is harness `pi`, model `openrouter/qwen/qwen3.7-plus`, vendor `alibaba`, and it is writer #2. `agy-gemini-4-argon-high` is harness `agy`, model `gemini-4-argon-high`, vendor `google`. `kxm role list` prints the first route id as the primary, for example `(grok-grok-4-7)`. The previous ids `grok-native` and `gemini-agy` are aliases. `gemini-agy` resolves to `agy-gemini-4-argon-high`. `qwen-openrouter-pi` is not an alias: it belonged to retired `pi-qwen3-coder-plus-openrouter` (`openrouter/qwen/qwen3-coder-plus`, catalog 404) and does not resolve to `pi-qwen3-7-plus-openrouter`.
|
|
169
169
|
|
|
170
170
|
Dispatch resolves a step from the agent `role`, then `.kxm/roles/<role>.yaml`, then the selected `.kxm/models/<route>.yaml`. That model file carries `harness`, `model`, `vendor`, `status`, and `permissions`. The engine walks the roster in order and uses the first admitted route whose model file is readable. A missing or unreadable model file is a refusal (`roster_model_unreadable` at load, `producer_route_unsupported` at dispatch), not a skip to the next entry. A route file that names a harness the model cannot run on still fails closed with `harness_unhosted_model`.
|
|
171
171
|
|
|
@@ -176,7 +176,7 @@ Role files are what `kxm role` and the Runtime membership check use.
|
|
|
176
176
|
`kxm routes list` prints one line per decision, for example:
|
|
177
177
|
|
|
178
178
|
```text
|
|
179
|
-
admitted openrouter/qwen/qwen3-
|
|
179
|
+
admitted openrouter/qwen/qwen3.7-plus
|
|
180
180
|
admitted xai/grok-4.7
|
|
181
181
|
disabled openrouter/x-ai/grok-4.7
|
|
182
182
|
```
|
|
@@ -201,7 +201,7 @@ The first segment of an id is the provider, and the rest is the model id. A rout
|
|
|
201
201
|
`kxm routes admit --model <id>` only takes an id that exists in `.kxm/models/inventory.yaml`. The inventory is a different namespace from these selectors (next section), and it never carries an `openrouter/…` selector, so a dry run refuses one:
|
|
202
202
|
|
|
203
203
|
```bash
|
|
204
|
-
kxm routes admit --model openrouter/qwen/qwen3-
|
|
204
|
+
kxm routes admit --model openrouter/qwen/qwen3.7-plus --dry-run
|
|
205
205
|
```
|
|
206
206
|
|
|
207
207
|
```text
|
|
@@ -252,7 +252,7 @@ The brake runs wherever KXM starts Pi on a model: in the dispatch probe that eac
|
|
|
252
252
|
| A Pi provider that belongs to the vendor | `openai-codex/…`, `moonshotai/…`, `moonshotai-cn/…`, `kimi-coding/…`, `google-vertex/…`, `claude-bridge/…`, and `antigravity/…` except Gemini ids | `pi provider openai-codex bills native vendor openai for gpt-6.1-sol; use the native harness` |
|
|
253
253
|
| The vendor segment of an aggregator id, including the aliases `x-ai`, `moonshotai` and `google-ai` | `openrouter/x-ai/grok-4.6`, `openrouter/anthropic/claude-fable-5.1`, `nous-portal/google/…` | `pi must not bill native vendor xai through openrouter; use the native harness` |
|
|
254
254
|
|
|
255
|
-
The brake accepts `antigravity/gemini-…` and any id whose vendor has no native harness, such as `openrouter/qwen/qwen3-
|
|
255
|
+
The brake accepts `antigravity/gemini-…` and any id whose vendor has no native harness, such as `openrouter/qwen/qwen3.7-plus`, `zai-coding-cn/glm-5.3` or `qwen-token-plan/qwen3.8-flash`. Passing the brake is not admission: the route must still be admitted. The hosting refusal at dispatch reads `grok_not_authenticated: grok harness not detected (harness_unhosted_model)`.
|
|
256
256
|
|
|
257
257
|
To run the load-time check, which covers only agents that declare a harness and select a profile or tag, run the read-only validation:
|
|
258
258
|
|
|
@@ -452,7 +452,7 @@ Admit an `antigravity/…` route only through a reviewed admission decision. The
|
|
|
452
452
|
Pi is the right harness when the vendor has no native harness in KXM, for example Qwen (Alibaba) and GLM (Z.ai). The choice is then between the vendor's own plan provider in Pi and an aggregator:
|
|
453
453
|
|
|
454
454
|
- Prefer the vendor-plan provider when `pi auth check` reports it `ready`, for example `qwen-token-plan/qwen3.8-flash` or `zai-coding-cn/glm-5.3`.
|
|
455
|
-
- Otherwise use an aggregator selector, such as `openrouter/qwen/qwen3-
|
|
455
|
+
- Otherwise use an aggregator selector, such as `openrouter/qwen/qwen3.7-plus`.
|
|
456
456
|
- Admit the exact selector, with the permission it needs, never a whole provider.
|
|
457
457
|
|
|
458
458
|
DeepSeek has a native harness entry, but it is never eligible: its auth is always `unknown`, and it has no audited read-only profile. A DeepSeek model billed through another vendor's plan, such as `qwen-token-plan/deepseek-…`, passes the brake because its id names no vendor segment. It is an admission question, not a precedent.
|
|
@@ -497,7 +497,7 @@ Each of those is a fail-closed stop, or a new admission decision.
|
|
|
497
497
|
| `pi auth check --provider nous-portal` or `--provider antigravity` returns `provider_not_found`. | The provider comes from a Pi package or the KXM Pi extension, and `pi auth check` never loads extensions, not even one passed with `-e`. | Confirm with `pi list` and `pi --list-models <id>`. The Runtime's Pi one-shot runs with `--no-extensions` and checks readiness with `pi auth check`, so it cannot reach extension providers. |
|
|
498
498
|
| `producer_route_unsupported: model '<selector>' is not admitted`, or `producer_route_not_admitted`. | The selector is missing from `admitted` in `.kxm/routes.yaml`, or it is under `disabled`. | Check with `kxm routes list`. After a reviewed decision, run `kxm routes admit --model <id>`, or edit the file when the inventory lacks the id. |
|
|
499
499
|
| `producer_route_unsupported: model '<selector>' not in role '<role>' roster` | The role file exists and does not list the selector. | Add it to `.kxm/roles/<role>.yaml` by Git review, and check with `kxm role get <role>`. |
|
|
500
|
-
| `pi_native_impersonation_blocked`, at dispatch or when a worker starts. | A Pi agent or worker names a native vendor's model: directly, through that vendor's Pi provider, or behind an aggregator. | Use the native harness (`harness: grok` for `provider: xai`), or an admitted Pi route whose vendor has no native harness, such as `openrouter/qwen/qwen3-
|
|
500
|
+
| `pi_native_impersonation_blocked`, at dispatch or when a worker starts. | A Pi agent or worker names a native vendor's model: directly, through that vendor's Pi provider, or behind an aggregator. | Use the native harness (`harness: grok` for `provider: xai`), or an admitted Pi route whose vendor has no native harness, such as `openrouter/qwen/qwen3.7-plus`. |
|
|
501
501
|
| `grok_not_authenticated: grok harness not detected (harness_unhosted_model)`, or `harness grok does not host provider openrouter`. | A native-harness agent was given an aggregator or another vendor's selector, often from a mixed role roster. | Give that selector its own agent with `harness:` omitted. |
|
|
502
502
|
| `routing report` shows every attempt under `Unk*`, and records carry `costBasis: unknown`. | Grok and every Pi route are recorded as `unknown` today. That is the design, not a missing price. | Nothing to fix per run. Compare quality and latency, and use list estimates for cost. |
|
|
503
503
|
| `providerMetadata.priceCatalogStale: true`, and there is no `listCostUsd`. | `.kxm/prices.yaml` is not dated today, or no row matches the route's provider. | Edit `.kxm/prices.yaml` by Git review: add a row for the provider, then update `date` and `sha256`. The loader refuses a hash mismatch. |
|
package/package.json
CHANGED
|
@@ -1167,7 +1167,7 @@ function evaluatePlanOptimizations(tasks) {
|
|
|
1167
1167
|
projectedTimeSavingsSeconds: 5,
|
|
1168
1168
|
projectedCostSavingsPercent: 65,
|
|
1169
1169
|
suggestedHarness: "pi",
|
|
1170
|
-
suggestedModel: "qwen/qwen3-
|
|
1170
|
+
suggestedModel: "qwen/qwen3.7-plus",
|
|
1171
1171
|
selected: true
|
|
1172
1172
|
});
|
|
1173
1173
|
} else if (isFrontier && (task.category === "lint" || /lint|format|style/i.test(task.title))) {
|
|
@@ -84,7 +84,7 @@ export function evaluatePlanOptimizations(tasks: readonly OptimizerTaskInput[]):
|
|
|
84
84
|
projectedTimeSavingsSeconds: 5,
|
|
85
85
|
projectedCostSavingsPercent: 65,
|
|
86
86
|
suggestedHarness: "pi",
|
|
87
|
-
suggestedModel: "qwen/qwen3-
|
|
87
|
+
suggestedModel: "qwen/qwen3.7-plus",
|
|
88
88
|
selected: true,
|
|
89
89
|
});
|
|
90
90
|
} else if (isFrontier && (task.category === "lint" || /lint|format|style/i.test(task.title))) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "kxm",
|
|
4
4
|
"displayName": "KXM",
|
|
5
|
-
"version": "0.7.
|
|
5
|
+
"version": "0.7.186",
|
|
6
6
|
"description": "Headless multi-agent orchestration, durable workflows, and a live operator dashboard for Pi and Claude Code",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "KontextMind",
|
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -18541,9 +18541,14 @@ function lintWorkforce(root) {
|
|
|
18541
18541
|
if (!expected || model.id !== expected) {
|
|
18542
18542
|
push(errors, "error", "route_id_convention", `.kxm/models/${model.id}.yaml`, `route id '${model.id}' must be '${expected ?? "<harness>-<model-slug>[-<provider>]"}'`);
|
|
18543
18543
|
}
|
|
18544
|
-
|
|
18544
|
+
const retired = doc.status === "retired";
|
|
18545
|
+
if (retired && used.has(model.id)) {
|
|
18546
|
+
push(errors, "error", "route_not_admitted", `.kxm/models/${model.id}.yaml`, `retired route '${model.id}' is still on a role roster`);
|
|
18547
|
+
}
|
|
18548
|
+
if (!retired && !used.has(model.id)) {
|
|
18545
18549
|
push(errors, "error", "route_unused", `.kxm/models/${model.id}.yaml`, `route '${model.id}' is not on any role roster`);
|
|
18546
18550
|
}
|
|
18551
|
+
if (retired) continue;
|
|
18547
18552
|
const selectorHit = selectorsFor(doc).find((selector) => admitted.includes(selector));
|
|
18548
18553
|
if (!selectorHit) {
|
|
18549
18554
|
push(errors, "error", "route_not_admitted", `.kxm/models/${model.id}.yaml`, `model '${doc.model ?? ""}' is not an admitted selector`);
|
|
@@ -18614,7 +18619,6 @@ var init_workforce_names = __esm({
|
|
|
18614
18619
|
]);
|
|
18615
18620
|
ROUTE_RENAMES = Object.freeze([
|
|
18616
18621
|
["grok-native", "grok-grok-4-7"],
|
|
18617
|
-
["qwen-openrouter-pi", "pi-qwen3-coder-plus-openrouter"],
|
|
18618
18622
|
["gemini-agy", "agy-gemini-4-argon-high"],
|
|
18619
18623
|
["fable-claude", "claude-fable"],
|
|
18620
18624
|
// sol-codex stays the GPT-5.6 route. codex-gpt-6-1-sol is a separate route.
|
|
@@ -56721,7 +56725,7 @@ var ADMITTED_GUIDE_BINDINGS = Object.freeze({
|
|
|
56721
56725
|
"openai/gpt-5.6-sol": { harness: "codex", provider: "openai", model: "gpt-5.6-sol" },
|
|
56722
56726
|
"x-ai/grok-4.6": { harness: "grok", provider: "xai", model: "grok-4.6" },
|
|
56723
56727
|
"xai/grok-4.6": { harness: "grok", provider: "xai", model: "grok-4.6" },
|
|
56724
|
-
"qwen/qwen3-
|
|
56728
|
+
"qwen/qwen3.7-plus": { harness: "pi", provider: "openrouter", model: "qwen/qwen3.7-plus" }
|
|
56725
56729
|
});
|
|
56726
56730
|
var GUIDE_WORKFLOWS = [
|
|
56727
56731
|
{
|
|
@@ -56752,7 +56756,7 @@ var GUIDE_WORKFLOWS = [
|
|
|
56752
56756
|
{ vendor: "openai", model: "gpt-5.6-sol" },
|
|
56753
56757
|
{ vendor: "deepseek", model: "deepseek-v4-pro-0813" },
|
|
56754
56758
|
{ vendor: "google", model: "gemini-3.8-flash" },
|
|
56755
|
-
{ vendor: "qwen", model: "qwen3-
|
|
56759
|
+
{ vendor: "qwen", model: "qwen3.7-plus" },
|
|
56756
56760
|
{ vendor: "anthropic", model: "claude-fable-5.1" }
|
|
56757
56761
|
]
|
|
56758
56762
|
},
|
|
@@ -56764,7 +56768,7 @@ var GUIDE_WORKFLOWS = [
|
|
|
56764
56768
|
candidates: [
|
|
56765
56769
|
{ vendor: "x-ai", model: "grok-4.6" },
|
|
56766
56770
|
{ vendor: "mistralai", model: "devstral-2512" },
|
|
56767
|
-
{ vendor: "qwen", model: "qwen3-
|
|
56771
|
+
{ vendor: "qwen", model: "qwen3.7-plus" },
|
|
56768
56772
|
{ vendor: "openai", model: "gpt-5.3-codex" },
|
|
56769
56773
|
{ vendor: "kwaipilot", model: "kat-coder-pro-v2.5" }
|
|
56770
56774
|
]
|
|
@@ -56776,7 +56780,7 @@ var GUIDE_WORKFLOWS = [
|
|
|
56776
56780
|
domain: "Implements domain entities, SQL queries/migrations, ORM persistence, concurrency primitives, and transactional boundaries.",
|
|
56777
56781
|
candidates: [
|
|
56778
56782
|
{ vendor: "x-ai", model: "grok-4.6" },
|
|
56779
|
-
{ vendor: "qwen", model: "qwen3-
|
|
56783
|
+
{ vendor: "qwen", model: "qwen3.7-plus" },
|
|
56780
56784
|
{ vendor: "deepseek", model: "deepseek-v4-pro-0813" },
|
|
56781
56785
|
{ vendor: "openai", model: "gpt-5.3-codex" },
|
|
56782
56786
|
{ vendor: "kwaipilot", model: "kat-coder-pro-v2.5" }
|
|
@@ -56803,7 +56807,7 @@ var GUIDE_WORKFLOWS = [
|
|
|
56803
56807
|
candidates: [
|
|
56804
56808
|
{ vendor: "openai", model: "gpt-5.6-sol" },
|
|
56805
56809
|
{ vendor: "x-ai", model: "grok-4.6" },
|
|
56806
|
-
{ vendor: "qwen", model: "qwen3-
|
|
56810
|
+
{ vendor: "qwen", model: "qwen3.7-plus" },
|
|
56807
56811
|
{ vendor: "deepseek", model: "deepseek-v4-pro-0813" },
|
|
56808
56812
|
{ vendor: "google", model: "gemini-3.8-flash" }
|
|
56809
56813
|
]
|
|
@@ -56930,7 +56934,7 @@ var GUIDE_WORKFLOWS = [
|
|
|
56930
56934
|
domain: "Generates declarative Terraform/OpenTofu, Pulumi, Kubernetes CRDs, and VPC networking definitions.",
|
|
56931
56935
|
candidates: [
|
|
56932
56936
|
{ vendor: "x-ai", model: "grok-4.6" },
|
|
56933
|
-
{ vendor: "qwen", model: "qwen3-
|
|
56937
|
+
{ vendor: "qwen", model: "qwen3.7-plus" },
|
|
56934
56938
|
{ vendor: "openai", model: "gpt-5.3-codex" },
|
|
56935
56939
|
{ vendor: "google", model: "gemini-3.8-flash" },
|
|
56936
56940
|
{ vendor: "mistralai", model: "devstral-2512" }
|
|
@@ -56990,7 +56994,7 @@ var GUIDE_WORKFLOWS = [
|
|
|
56990
56994
|
domain: "Authors concise, accurate developer and operator documentation with clear terminology, correct command flags, and consistent formatting without marketing drift.",
|
|
56991
56995
|
candidates: [
|
|
56992
56996
|
{ vendor: "x-ai", model: "grok-4.6" },
|
|
56993
|
-
{ vendor: "qwen", model: "qwen3-
|
|
56997
|
+
{ vendor: "qwen", model: "qwen3.7-plus" },
|
|
56994
56998
|
{ vendor: "anthropic", model: "claude-sonnet-5" },
|
|
56995
56999
|
{ vendor: "openai", model: "gpt-5.3-codex" },
|
|
56996
57000
|
{ vendor: "deepseek", model: "deepseek-v4-pro-0813" }
|
|
@@ -57095,11 +57099,11 @@ function workflowDocument(workflow) {
|
|
|
57095
57099
|
};
|
|
57096
57100
|
}
|
|
57097
57101
|
var GUIDE_PI_EVIDENCE_SOURCE = "plans/evidence/route-guide-qwen-pi.md";
|
|
57098
|
-
var GUIDE_PI_EVIDENCE_SHA256 = "
|
|
57102
|
+
var GUIDE_PI_EVIDENCE_SHA256 = "8a24a7dc6db416df2153cfec7bccf1a4462f838e35c4e6707dc421ca84cf069b";
|
|
57099
57103
|
var GUIDE_PI_NOTE = {
|
|
57100
57104
|
harness: "pi",
|
|
57101
57105
|
vendor: "openrouter",
|
|
57102
|
-
model: "qwen/qwen3-
|
|
57106
|
+
model: "qwen/qwen3.7-plus",
|
|
57103
57107
|
reason: "Qwen has no supported native harness on this runner, and the operator admitted that exact model for guided setup.",
|
|
57104
57108
|
provingCommand: "pi auth check --provider openrouter"
|
|
57105
57109
|
};
|
|
@@ -58101,7 +58105,7 @@ async function cmdRoutingReport(runtime, options) {
|
|
|
58101
58105
|
}
|
|
58102
58106
|
async function cmdRoutingBenchmark(runtime, options) {
|
|
58103
58107
|
const task = options.task || "Deterministic benchmark task";
|
|
58104
|
-
const armsStr = options.arms || "grok/grok-4.6,claude/fable,pi/qwen3-
|
|
58108
|
+
const armsStr = options.arms || "grok/grok-4.6,claude/fable,pi/qwen3.7-plus";
|
|
58105
58109
|
const armsList = armsStr.split(",").map((s) => s.trim()).filter(Boolean);
|
|
58106
58110
|
const runsCount = Math.max(1, parseInt(options.runs || "1", 10) || 1);
|
|
58107
58111
|
const arms = armsList.map((arm) => {
|
|
@@ -25462,7 +25462,7 @@ function sessionTokenFixHint(policy) {
|
|
|
25462
25462
|
}
|
|
25463
25463
|
|
|
25464
25464
|
// plugins/kxm/src/mcp-server.ts
|
|
25465
|
-
var VERSION = "0.7.
|
|
25465
|
+
var VERSION = "0.7.186";
|
|
25466
25466
|
var CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
|
|
25467
25467
|
var inbox = /* @__PURE__ */ new Map();
|
|
25468
25468
|
var notifiedInbox = /* @__PURE__ */ new Set();
|
|
@@ -15543,7 +15543,6 @@ var ROLE_IDS = Object.freeze([
|
|
|
15543
15543
|
]);
|
|
15544
15544
|
var ROUTE_RENAMES = Object.freeze([
|
|
15545
15545
|
["grok-native", "grok-grok-4-7"],
|
|
15546
|
-
["qwen-openrouter-pi", "pi-qwen3-coder-plus-openrouter"],
|
|
15547
15546
|
["gemini-agy", "agy-gemini-4-argon-high"],
|
|
15548
15547
|
["fable-claude", "claude-fable"],
|
|
15549
15548
|
// sol-codex stays the GPT-5.6 route. codex-gpt-6-1-sol is a separate route.
|
|
@@ -15735,9 +15734,14 @@ function lintWorkforce(root) {
|
|
|
15735
15734
|
if (!expected || model.id !== expected) {
|
|
15736
15735
|
push(errors, "error", "route_id_convention", `.kxm/models/${model.id}.yaml`, `route id '${model.id}' must be '${expected ?? "<harness>-<model-slug>[-<provider>]"}'`);
|
|
15737
15736
|
}
|
|
15738
|
-
|
|
15737
|
+
const retired = doc.status === "retired";
|
|
15738
|
+
if (retired && used.has(model.id)) {
|
|
15739
|
+
push(errors, "error", "route_not_admitted", `.kxm/models/${model.id}.yaml`, `retired route '${model.id}' is still on a role roster`);
|
|
15740
|
+
}
|
|
15741
|
+
if (!retired && !used.has(model.id)) {
|
|
15739
15742
|
push(errors, "error", "route_unused", `.kxm/models/${model.id}.yaml`, `route '${model.id}' is not on any role roster`);
|
|
15740
15743
|
}
|
|
15744
|
+
if (retired) continue;
|
|
15741
15745
|
const selectorHit = selectorsFor(doc).find((selector) => admitted.includes(selector));
|
|
15742
15746
|
if (!selectorHit) {
|
|
15743
15747
|
push(errors, "error", "route_not_admitted", `.kxm/models/${model.id}.yaml`, `model '${doc.model ?? ""}' is not an admitted selector`);
|
|
@@ -15516,7 +15516,6 @@ var ROLE_IDS = Object.freeze([
|
|
|
15516
15516
|
]);
|
|
15517
15517
|
var ROUTE_RENAMES = Object.freeze([
|
|
15518
15518
|
["grok-native", "grok-grok-4-7"],
|
|
15519
|
-
["qwen-openrouter-pi", "pi-qwen3-coder-plus-openrouter"],
|
|
15520
15519
|
["gemini-agy", "agy-gemini-4-argon-high"],
|
|
15521
15520
|
["fable-claude", "claude-fable"],
|
|
15522
15521
|
// sol-codex stays the GPT-5.6 route. codex-gpt-6-1-sol is a separate route.
|
|
@@ -15708,9 +15707,14 @@ function lintWorkforce(root) {
|
|
|
15708
15707
|
if (!expected || model.id !== expected) {
|
|
15709
15708
|
push(errors, "error", "route_id_convention", `.kxm/models/${model.id}.yaml`, `route id '${model.id}' must be '${expected ?? "<harness>-<model-slug>[-<provider>]"}'`);
|
|
15710
15709
|
}
|
|
15711
|
-
|
|
15710
|
+
const retired = doc.status === "retired";
|
|
15711
|
+
if (retired && used.has(model.id)) {
|
|
15712
|
+
push(errors, "error", "route_not_admitted", `.kxm/models/${model.id}.yaml`, `retired route '${model.id}' is still on a role roster`);
|
|
15713
|
+
}
|
|
15714
|
+
if (!retired && !used.has(model.id)) {
|
|
15712
15715
|
push(errors, "error", "route_unused", `.kxm/models/${model.id}.yaml`, `route '${model.id}' is not on any role roster`);
|
|
15713
15716
|
}
|
|
15717
|
+
if (retired) continue;
|
|
15714
15718
|
const selectorHit = selectorsFor(doc).find((selector) => admitted.includes(selector));
|
|
15715
15719
|
if (!selectorHit) {
|
|
15716
15720
|
push(errors, "error", "route_not_admitted", `.kxm/models/${model.id}.yaml`, `model '${doc.model ?? ""}' is not an admitted selector`);
|
|
@@ -36447,7 +36451,7 @@ var SUBAGENT_TYPES = Object.freeze([
|
|
|
36447
36451
|
]);
|
|
36448
36452
|
var DEFAULT_SUBAGENT_MODELS = Object.freeze({
|
|
36449
36453
|
general: "grok/grok-4.6",
|
|
36450
|
-
Explore: "openrouter/qwen/qwen3-
|
|
36454
|
+
Explore: "openrouter/qwen/qwen3.7-plus",
|
|
36451
36455
|
Plan: "claude/fable",
|
|
36452
36456
|
Reviewer: "openai/gpt-5.6-sol",
|
|
36453
36457
|
Auditor: "claude/fable"
|
|
@@ -15008,7 +15008,6 @@ var ROLE_IDS = Object.freeze([
|
|
|
15008
15008
|
]);
|
|
15009
15009
|
var ROUTE_RENAMES = Object.freeze([
|
|
15010
15010
|
["grok-native", "grok-grok-4-7"],
|
|
15011
|
-
["qwen-openrouter-pi", "pi-qwen3-coder-plus-openrouter"],
|
|
15012
15011
|
["gemini-agy", "agy-gemini-4-argon-high"],
|
|
15013
15012
|
["fable-claude", "claude-fable"],
|
|
15014
15013
|
// sol-codex stays the GPT-5.6 route. codex-gpt-6-1-sol is a separate route.
|
package/plugins/kxm/package.json
CHANGED
|
@@ -1071,7 +1071,7 @@ export async function cmdRoutingBenchmark(
|
|
|
1071
1071
|
options: { task?: string | undefined; arms?: string | undefined; runs?: string | undefined },
|
|
1072
1072
|
): Promise<number> {
|
|
1073
1073
|
const task = options.task || "Deterministic benchmark task";
|
|
1074
|
-
const armsStr = options.arms || "grok/grok-4.6,claude/fable,pi/qwen3-
|
|
1074
|
+
const armsStr = options.arms || "grok/grok-4.6,claude/fable,pi/qwen3.7-plus";
|
|
1075
1075
|
const armsList = armsStr.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1076
1076
|
const runsCount = Math.max(1, parseInt(options.runs || "1", 10) || 1);
|
|
1077
1077
|
|
|
@@ -64,7 +64,7 @@ const ADMITTED_GUIDE_BINDINGS: Readonly<Record<string, AgentBinding>> = Object.f
|
|
|
64
64
|
"openai/gpt-5.6-sol": { harness: "codex", provider: "openai", model: "gpt-5.6-sol" },
|
|
65
65
|
"x-ai/grok-4.6": { harness: "grok", provider: "xai", model: "grok-4.6" },
|
|
66
66
|
"xai/grok-4.6": { harness: "grok", provider: "xai", model: "grok-4.6" },
|
|
67
|
-
"qwen/qwen3-
|
|
67
|
+
"qwen/qwen3.7-plus": { harness: "pi", provider: "openrouter", model: "qwen/qwen3.7-plus" },
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
/** Guide candidates are ordered by preference; the first eligible wins. */
|
|
@@ -97,7 +97,7 @@ export const GUIDE_WORKFLOWS: readonly GuideWorkflow[] = [
|
|
|
97
97
|
{ vendor: "openai", model: "gpt-5.6-sol" },
|
|
98
98
|
{ vendor: "deepseek", model: "deepseek-v4-pro-0813" },
|
|
99
99
|
{ vendor: "google", model: "gemini-3.8-flash" },
|
|
100
|
-
{ vendor: "qwen", model: "qwen3-
|
|
100
|
+
{ vendor: "qwen", model: "qwen3.7-plus" },
|
|
101
101
|
{ vendor: "anthropic", model: "claude-fable-5.1" },
|
|
102
102
|
],
|
|
103
103
|
},
|
|
@@ -109,7 +109,7 @@ export const GUIDE_WORKFLOWS: readonly GuideWorkflow[] = [
|
|
|
109
109
|
candidates: [
|
|
110
110
|
{ vendor: "x-ai", model: "grok-4.6" },
|
|
111
111
|
{ vendor: "mistralai", model: "devstral-2512" },
|
|
112
|
-
{ vendor: "qwen", model: "qwen3-
|
|
112
|
+
{ vendor: "qwen", model: "qwen3.7-plus" },
|
|
113
113
|
{ vendor: "openai", model: "gpt-5.3-codex" },
|
|
114
114
|
{ vendor: "kwaipilot", model: "kat-coder-pro-v2.5" },
|
|
115
115
|
],
|
|
@@ -121,7 +121,7 @@ export const GUIDE_WORKFLOWS: readonly GuideWorkflow[] = [
|
|
|
121
121
|
domain: "Implements domain entities, SQL queries/migrations, ORM persistence, concurrency primitives, and transactional boundaries.",
|
|
122
122
|
candidates: [
|
|
123
123
|
{ vendor: "x-ai", model: "grok-4.6" },
|
|
124
|
-
{ vendor: "qwen", model: "qwen3-
|
|
124
|
+
{ vendor: "qwen", model: "qwen3.7-plus" },
|
|
125
125
|
{ vendor: "deepseek", model: "deepseek-v4-pro-0813" },
|
|
126
126
|
{ vendor: "openai", model: "gpt-5.3-codex" },
|
|
127
127
|
{ vendor: "kwaipilot", model: "kat-coder-pro-v2.5" },
|
|
@@ -148,7 +148,7 @@ export const GUIDE_WORKFLOWS: readonly GuideWorkflow[] = [
|
|
|
148
148
|
candidates: [
|
|
149
149
|
{ vendor: "openai", model: "gpt-5.6-sol" },
|
|
150
150
|
{ vendor: "x-ai", model: "grok-4.6" },
|
|
151
|
-
{ vendor: "qwen", model: "qwen3-
|
|
151
|
+
{ vendor: "qwen", model: "qwen3.7-plus" },
|
|
152
152
|
{ vendor: "deepseek", model: "deepseek-v4-pro-0813" },
|
|
153
153
|
{ vendor: "google", model: "gemini-3.8-flash" },
|
|
154
154
|
],
|
|
@@ -275,7 +275,7 @@ export const GUIDE_WORKFLOWS: readonly GuideWorkflow[] = [
|
|
|
275
275
|
domain: "Generates declarative Terraform/OpenTofu, Pulumi, Kubernetes CRDs, and VPC networking definitions.",
|
|
276
276
|
candidates: [
|
|
277
277
|
{ vendor: "x-ai", model: "grok-4.6" },
|
|
278
|
-
{ vendor: "qwen", model: "qwen3-
|
|
278
|
+
{ vendor: "qwen", model: "qwen3.7-plus" },
|
|
279
279
|
{ vendor: "openai", model: "gpt-5.3-codex" },
|
|
280
280
|
{ vendor: "google", model: "gemini-3.8-flash" },
|
|
281
281
|
{ vendor: "mistralai", model: "devstral-2512" },
|
|
@@ -335,7 +335,7 @@ export const GUIDE_WORKFLOWS: readonly GuideWorkflow[] = [
|
|
|
335
335
|
domain: "Authors concise, accurate developer and operator documentation with clear terminology, correct command flags, and consistent formatting without marketing drift.",
|
|
336
336
|
candidates: [
|
|
337
337
|
{ vendor: "x-ai", model: "grok-4.6" },
|
|
338
|
-
{ vendor: "qwen", model: "qwen3-
|
|
338
|
+
{ vendor: "qwen", model: "qwen3.7-plus" },
|
|
339
339
|
{ vendor: "anthropic", model: "claude-sonnet-5" },
|
|
340
340
|
{ vendor: "openai", model: "gpt-5.3-codex" },
|
|
341
341
|
{ vendor: "deepseek", model: "deepseek-v4-pro-0813" },
|
|
@@ -490,11 +490,11 @@ function workflowDocument(workflow: GuideWorkflow): Record<string, unknown> {
|
|
|
490
490
|
* id, and harness gets no model file and no origin.
|
|
491
491
|
*/
|
|
492
492
|
const GUIDE_PI_EVIDENCE_SOURCE = "plans/evidence/route-guide-qwen-pi.md";
|
|
493
|
-
const GUIDE_PI_EVIDENCE_SHA256 = "
|
|
493
|
+
const GUIDE_PI_EVIDENCE_SHA256 = "8a24a7dc6db416df2153cfec7bccf1a4462f838e35c4e6707dc421ca84cf069b";
|
|
494
494
|
const GUIDE_PI_NOTE = {
|
|
495
495
|
harness: "pi",
|
|
496
496
|
vendor: "openrouter",
|
|
497
|
-
model: "qwen/qwen3-
|
|
497
|
+
model: "qwen/qwen3.7-plus",
|
|
498
498
|
reason: "Qwen has no supported native harness on this runner, and the operator admitted that exact model for guided setup.",
|
|
499
499
|
provingCommand: "pi auth check --provider openrouter",
|
|
500
500
|
} as const;
|
|
@@ -11,7 +11,7 @@ import { deliverInboxNotification } from "./inbox.ts";
|
|
|
11
11
|
import type { HubEvent, MessageRecord } from "./protocol.ts";
|
|
12
12
|
import { sessionTokenFixHint } from "./session-token-hint.ts";
|
|
13
13
|
|
|
14
|
-
const VERSION = "0.7.
|
|
14
|
+
const VERSION = "0.7.186";
|
|
15
15
|
const CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
|
|
16
16
|
const inbox = new Map<string, MessageRecord>();
|
|
17
17
|
const notifiedInbox = new Set<string>();
|
|
@@ -270,7 +270,7 @@ export function createKxmOneShotProducer(options: KxmOneShotProducerOptions = {}
|
|
|
270
270
|
): { provider: string; model: string; thinking?: string | undefined } {
|
|
271
271
|
if (request.model) {
|
|
272
272
|
// A separate provider field means the model id is bare and may itself be
|
|
273
|
-
// namespaced (openrouter + qwen/qwen3-
|
|
273
|
+
// namespaced (openrouter + qwen/qwen3.7-plus); reparsing it as a
|
|
274
274
|
// provider/model selector strips the namespace — the same defect #262 fixed
|
|
275
275
|
// in the pi producer. Only parse when the provider must come from the string.
|
|
276
276
|
if (request.provider) {
|
|
@@ -401,7 +401,7 @@ export function createKxmOneShotProducer(options: KxmOneShotProducerOptions = {}
|
|
|
401
401
|
// pi's model flag takes the provider-qualified id — exactly the auth probe's
|
|
402
402
|
// rule (#265): prefix with the provider unless the model already starts with it.
|
|
403
403
|
// A bare "contains a slash" test is wrong for provider-local namespaces
|
|
404
|
-
// (openrouter + qwen/qwen3-
|
|
404
|
+
// (openrouter + qwen/qwen3.7-plus must spawn as the full three-part id).
|
|
405
405
|
const qualified = resolved.provider && resolved.model.startsWith(`${resolved.provider}/`)
|
|
406
406
|
? resolved.model
|
|
407
407
|
: resolved.provider ? `${resolved.provider}/${resolved.model}` : resolved.model;
|
|
@@ -463,7 +463,7 @@ export function createKxmPiProducer(options: KxmPiProducerOptions = {}): KxmPiPr
|
|
|
463
463
|
function resolveModelForRequest(request: KxmProducerRequest): { provider: string; model: string; thinking?: string | undefined } {
|
|
464
464
|
if (request.model) {
|
|
465
465
|
// A separate provider field means the model id is bare and may itself be
|
|
466
|
-
// namespaced (`qwen/qwen3-
|
|
466
|
+
// namespaced (`qwen/qwen3.7-plus` under `openrouter`); reparsing it as a
|
|
467
467
|
// provider/model selector strips the namespace and sends the wrong model. Only
|
|
468
468
|
// parse when the provider must come from the string itself.
|
|
469
469
|
if (request.provider) {
|
|
@@ -77,7 +77,7 @@ export const SUBAGENT_TYPES: readonly SubagentType[] = Object.freeze([
|
|
|
77
77
|
|
|
78
78
|
export const DEFAULT_SUBAGENT_MODELS: Readonly<Record<SubagentType, string>> = Object.freeze({
|
|
79
79
|
general: "grok/grok-4.6",
|
|
80
|
-
Explore: "openrouter/qwen/qwen3-
|
|
80
|
+
Explore: "openrouter/qwen/qwen3.7-plus",
|
|
81
81
|
Plan: "claude/fable",
|
|
82
82
|
Reviewer: "openai/gpt-5.6-sol",
|
|
83
83
|
Auditor: "claude/fable",
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
* the assignment runner reads at one commit. A tree that has already renamed
|
|
13
13
|
* the files still accepts the old id. A mixed tree accepts either side.
|
|
14
14
|
* `opus-claude` is not renamed: that route pointed at an unadmitted model and
|
|
15
|
-
* was removed.
|
|
15
|
+
* was removed. `qwen-openrouter-pi` is not renamed either: it belonged to
|
|
16
|
+
* retired `pi-qwen3-coder-plus-openrouter` and does not resolve to
|
|
17
|
+
* `pi-qwen3-7-plus-openrouter`.
|
|
16
18
|
*/
|
|
17
19
|
|
|
18
20
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
@@ -32,7 +34,6 @@ export const ROLE_IDS = Object.freeze([
|
|
|
32
34
|
/** Old id, canonical id. Listed once; lookup tries both directions. */
|
|
33
35
|
export const ROUTE_RENAMES = Object.freeze([
|
|
34
36
|
["grok-native", "grok-grok-4-7"],
|
|
35
|
-
["qwen-openrouter-pi", "pi-qwen3-coder-plus-openrouter"],
|
|
36
37
|
["gemini-agy", "agy-gemini-4-argon-high"],
|
|
37
38
|
["fable-claude", "claude-fable"],
|
|
38
39
|
// sol-codex stays the GPT-5.6 route. codex-gpt-6-1-sol is a separate route.
|
|
@@ -191,7 +192,9 @@ function selectorsFor(doc) {
|
|
|
191
192
|
|
|
192
193
|
/**
|
|
193
194
|
* Lint one project's `.kxm` workforce. Errors fail CI. An admitted model with
|
|
194
|
-
* no route is a warning.
|
|
195
|
+
* no route is a warning. A model file with `status: retired` may stay off
|
|
196
|
+
* every roster and off `.kxm/routes.yaml`; a roster that still names it is
|
|
197
|
+
* `route_not_admitted`. Alias declarations are not uses; a roster or step
|
|
195
198
|
* that still cites an old id is a `deprecated_id` warning.
|
|
196
199
|
*/
|
|
197
200
|
export function lintWorkforce(root) {
|
|
@@ -257,9 +260,14 @@ export function lintWorkforce(root) {
|
|
|
257
260
|
if (!expected || model.id !== expected) {
|
|
258
261
|
push(errors, "error", "route_id_convention", `.kxm/models/${model.id}.yaml`, `route id '${model.id}' must be '${expected ?? "<harness>-<model-slug>[-<provider>]"}'`);
|
|
259
262
|
}
|
|
260
|
-
|
|
263
|
+
const retired = doc.status === "retired";
|
|
264
|
+
if (retired && used.has(model.id)) {
|
|
265
|
+
push(errors, "error", "route_not_admitted", `.kxm/models/${model.id}.yaml`, `retired route '${model.id}' is still on a role roster`);
|
|
266
|
+
}
|
|
267
|
+
if (!retired && !used.has(model.id)) {
|
|
261
268
|
push(errors, "error", "route_unused", `.kxm/models/${model.id}.yaml`, `route '${model.id}' is not on any role roster`);
|
|
262
269
|
}
|
|
270
|
+
if (retired) continue;
|
|
263
271
|
const selectorHit = selectorsFor(doc).find((selector) => admitted.includes(selector));
|
|
264
272
|
if (!selectorHit) {
|
|
265
273
|
push(errors, "error", "route_not_admitted", `.kxm/models/${model.id}.yaml`, `model '${doc.model ?? ""}' is not an admitted selector`);
|
|
@@ -19,7 +19,7 @@ export const PI_ALLOWED_PROVIDERS: readonly string[];
|
|
|
19
19
|
export const PI_NATIVE_VENDOR_PROVIDERS: Readonly<Record<string, string>>;
|
|
20
20
|
export const PI_ANTIGRAVITY_MODEL_ID: RegExp;
|
|
21
21
|
export const PI_NOUS_PORTAL_HY4: "nous-portal/tencent/hy4-preview";
|
|
22
|
-
export const PI_ADMITTED_WRITER: "openrouter/qwen/qwen3-
|
|
22
|
+
export const PI_ADMITTED_WRITER: "openrouter/qwen/qwen3.7-plus";
|
|
23
23
|
export const ROUTES: Record<string, {
|
|
24
24
|
provider: string;
|
|
25
25
|
roles: readonly string[];
|
package/scripts/harness-run.mjs
CHANGED
|
@@ -88,7 +88,7 @@ export const PI_ANTIGRAVITY_MODEL_ID = /^gemini-[a-z0-9.-]+$/;
|
|
|
88
88
|
export const PI_NOUS_PORTAL_HY4 = "nous-portal/tencent/hy4-preview";
|
|
89
89
|
|
|
90
90
|
/** Narrowly admitted Pi writer. Other Pi models need reviewed route admission. */
|
|
91
|
-
export const PI_ADMITTED_WRITER = "openrouter/qwen/qwen3-
|
|
91
|
+
export const PI_ADMITTED_WRITER = "openrouter/qwen/qwen3.7-plus";
|
|
92
92
|
|
|
93
93
|
const REQUEST_KEYS = Object.freeze([
|
|
94
94
|
"schema",
|
|
@@ -1555,7 +1555,7 @@ export function preflightRequest(request) {
|
|
|
1555
1555
|
}
|
|
1556
1556
|
}
|
|
1557
1557
|
if (request.role === "writer" && (request.model !== PI_ADMITTED_WRITER || request.permission !== "edit")) {
|
|
1558
|
-
throw failClosed("pi writer refuses unsupported route; allows only authenticated openrouter/qwen/qwen3-
|
|
1558
|
+
throw failClosed("pi writer refuses unsupported route; allows only authenticated openrouter/qwen/qwen3.7-plus with edit permission; other models need reviewed route admission");
|
|
1559
1559
|
}
|
|
1560
1560
|
const segment = piProviderOf(piModelId(request.model));
|
|
1561
1561
|
const vendor = segment && Object.hasOwn(PI_VENDOR_SEGMENT_ALIASES, segment) ? PI_VENDOR_SEGMENT_ALIASES[segment] : segment;
|