@kontextmind/kxm 0.7.149 → 0.7.151

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.
@@ -11,7 +11,7 @@
11
11
  "name": "kxm",
12
12
  "source": "./plugins/kxm",
13
13
  "description": "Durable workflows, peer agents, and kxm tui",
14
- "version": "0.7.149",
14
+ "version": "0.7.151",
15
15
  "category": "development",
16
16
  "tags": ["kxm", "multi-agent", "workflows", "mcp"]
17
17
  }
package/CHANGELOG.md CHANGED
@@ -6,6 +6,20 @@ All notable user-facing changes are documented here. The project follows [Semant
6
6
 
7
7
  ### Added
8
8
 
9
+ - **An opted-in role continues a failed attempt on the next admitted route.**
10
+ `policy.fallback.onError` lists `rate_limit`, `transport`,
11
+ `provider_unavailable`, and `context_overflow`. An empty or absent list is
12
+ unchanged: the attempt fails on the first route. The walk is bounded by
13
+ `maxSwitches` (default 1), skips a critic-vendor collision when the role
14
+ requires vendor independence, and records `routing.route_switched` plus a
15
+ `route_switch` log line. A bounded redacted transcript is appended to the
16
+ next prompt. `revert: never` keeps the successful route for later steps in
17
+ the same run. `kxm routing report` and `kxm improve report` show the switch.
18
+ Cancellation, policy refusal, authentication, an unhosted model, a gate
19
+ failure, tool policy, and admission errors do not walk. See
20
+ [role fallback](docs/reference/config-reference.md#kxmrolesroleyaml-kxmrolev2)
21
+ and [mid-attempt fallback](docs/reference/harness-routing.md#mid-attempt-fallback).
22
+
9
23
  - **A live agent step uses a configurable one-shot timeout, and a cancelling run recovers when its child has already exited.**
10
24
  The bound is the step `timeoutMs`, or the project `limits.agentStepTimeoutMs`
11
25
  when the step omits it (minimum 60 seconds, default one hour). A wider step
@@ -14,6 +14,11 @@ a checkout fingerprint, invokes the producer, then fingerprints again
14
14
  does not change the tree cannot stay `passed`. A read-only step that changes
15
15
  the tree cannot stay `passed`.
16
16
 
17
+ When the step's role lists the failure on `policy.fallback.onError`, a
18
+ walkable producer error is redispatched on the next admitted route before the
19
+ attempt settles. The engine records `routing.route_switched` and logs
20
+ `route_switch`. An empty or absent list does not take this path.
21
+
17
22
  ```mermaid
18
23
  sequenceDiagram
19
24
  participant CLI as kxm CLI
@@ -207,6 +207,7 @@ A gate step declares an outcome its `expect` value never produces. The message n
207
207
  | `runtime_supervisor_unreachable` | A live supervisor process does not answer its token probe | Check the PID from `kxm runtime status`, stop a hung process with your OS tools, then `kxm runtime start` |
208
208
  | `project_required` | The command ran outside a KXM project | Run it from the checkout, or run `kxm init` |
209
209
  | `producer_route_not_admitted` | A live drive uses a model route that is not admitted | `kxm routes admit --model <provider/model>`, or drive with `--simulated` |
210
+ | A 429, timeout, or provider error fails the attempt on the first route | The role's `policy.fallback.onError` is empty, omits that class, or `maxSwitches` is already spent. Cancellation, policy refusal, and authentication do not walk | List the class on the role, admit the next route, and read `routing.route_switched` in the run events. `kxm routing report` prints Route switches |
210
211
  | `pi_not_authenticated: pi harness not detected (pi_native_impersonation_blocked)` | A Pi agent's model belongs to a vendor with its own harness | Set the agent's native `harness:`, or choose an admitted Pi route whose vendor has none |
211
212
  | `run_busy` (HTTP 409) | The run is already admitted or queued for a drive | Wait, and check `kxm runs status <run-id>` |
212
213
  | A run store is refused with `runtime_schema_outdated` | The store predates this release | See [Upgrade KXM](upgrade.md#understand-schema-changes) |
@@ -1688,7 +1688,7 @@ kxm runs status --dry-run refused: the Runtime supervisor is not running and --d
1688
1688
  kxm runs drive <runId> [--simulated] [--wait] [--timeout-ms <n>] [--lane <unit>]
1689
1689
  ```
1690
1690
 
1691
- Opens a drive of the run. With `--simulated`, a model-free producer reports every agent step as passed. Without `--simulated` the drive runs in live mode: each agent step invokes its harness through a one-shot producer, and the agent's model must be an admitted route (otherwise `producer_route_not_admitted`; there is no fallback model). A read-only step runs with the harness's read-only flags. A step with `write` access runs with an audited writer profile, which only `pi` and `grok` have; it must be a single assignment in a project whose `limits.maxConcurrentRuns` is 1, and its route must be on the writer roster in `.kxm/roles/writer.yaml`. Otherwise the drive hands the run off with `step_unsupported`. Around each live attempt the Runtime fingerprints the checkout with `git rev-parse HEAD`, `git status`, and `git diff`: a write step settles `passed` only when the checkout changed (routing metadata `authored: true`), and a read-only step that changed it settles `failed` (`authoringWitness: readonly_mutated`).
1691
+ Opens a drive of the run. With `--simulated`, a model-free producer reports every agent step as passed. Without `--simulated` the drive runs in live mode: each agent step invokes its harness through a one-shot producer, and the agent's model must be an admitted route (otherwise `producer_route_not_admitted`). When the role's `policy.fallback.onError` lists the failure class, the same attempt continues on the next admitted route and records `routing.route_switched`; an empty or absent list fails the attempt on the first route. A read-only step runs with the harness's read-only flags. A step with `write` access runs with an audited writer profile, which only `pi` and `grok` have; it must be a single assignment in a project whose `limits.maxConcurrentRuns` is 1, and its route must be on the writer roster in `.kxm/roles/writer.yaml`. Otherwise the drive hands the run off with `step_unsupported`. Around each live attempt the Runtime fingerprints the checkout with `git rev-parse HEAD`, `git status`, and `git diff`: a write step settles `passed` only when the checkout changed (routing metadata `authored: true`), and a read-only step that changed it settles `failed` (`authoringWitness: readonly_mutated`).
1692
1692
 
1693
1693
  | Option | Argument | Default | Description |
1694
1694
  |---|---|---|---|
@@ -3415,7 +3415,7 @@ Generate the improvement report and candidates from routing records. Inside a KX
3415
3415
  - Reads `improvement.*` from the project and user configuration (see [`kxm.config.v1`](config-reference.md#personalization-settings-kxmconfigv1)) and reports each candidate's promotion readiness under `improvement.promotionPolicy`. Readiness never authorizes anything. Under `critic_quorum` every candidate reports not ready, because this command cites no critic receipts. A configuration that cannot be loaded exits 1 with `config_invalid`.
3416
3416
  - A Runtime store that exists but cannot be read exits 1 with `improve_source_unreadable`; `detail` names the path.
3417
3417
  - Writes candidate files under `--out-dir` (relative to the current directory) and the report at `.kxm/assets/improvements/<timestamp>.json`. Honors `--dry-run` (writes neither). No hub needed.
3418
- - JSON keys: `path`, `events`, `recordsCount`, `groupsCount`, `candidatesCount`, `candidates`, `report` (`schema`, `createdAt`, `reviewDecision`, `recordsCount`, `groups`, `candidates`, `promotionPolicy`, `promotion`), `sources`, `projectRoot` (`null` outside a project).
3418
+ - JSON keys: `path`, `events`, `recordsCount`, `groupsCount`, `candidatesCount`, `candidates`, `report` (`schema`, `createdAt`, `reviewDecision`, `recordsCount`, `groups`, `candidates`, `promotionPolicy`, `promotion`, and `routeSwitches` when the store recorded any), `sources`, `projectRoot` (`null` outside a project). `routeSwitches` lists opted-in mid-attempt walks (`from`, `to`, `reason`, optional `effort`, `attemptId`, `stepId`). It is omitted when there are none.
3419
3419
  - Each `sources` entry has `kind` (`engine`, `telemetry`, or `file`), `path`, `exists`, `records`, and `duplicatesDropped`; the `engine` entry also has `skippedInvalid`, `excludedSimulated`, and `undecided`.
3420
3420
  - Each `report.groups` row has `workflowHash`, `workflowId` (Runtime records), `stepId`, `agentRole`, `promptHash`, `recurrence`, `distinctRuns`, `askRecurrence`, `undecidedRecords`, `meanCost`, `meanLatency`, `verifyPassRate` (accepted share of decided records), `rework`, `weightedRecurrence`, `undatedRecords`, `costSamples`, `writesRepository`, `evidenceRefs`, `isCandidate`, and, when they apply, `excludedReason`, `candidateKind`, and `candidateId`.
3421
3421
  - Each `report.promotion` entry has `candidateId`, `policy`, `readyForReview`, and `reason`.
@@ -3481,9 +3481,9 @@ Without `--file` it reads the same sources as [`kxm improve report`](#kxm-improv
3481
3481
  - `--equivalent-list-cost` loads the catalog without the freshness check the producers apply, so it prices with a catalog of any date, including one the producers treat as stale. Check the catalog `date` before you rely on `ListEquiv($)`.
3482
3482
  - A Runtime store that exists but cannot be read exits 1 with `improve_source_unreadable`.
3483
3483
  - Ranking: quality first (Pass%, then Rwk%), then cost per accepted attempt. Among routes of equal quality, any route with an unknown-cost attempt ranks after every route without one. Such a route's cost is unknown, not a partial sum: `$/Acc` prints `-` (JSON `costPerAcceptedUsd: null`) and the `*` in `Unk` marks it.
3484
- - The `Quota` column counts attempts whose metadata looks quota-exhausted (a quota failure class, a `quota` flag, or text such as `rate limit` or `HTTP 429`). It is a count only: nothing fails over to another route.
3484
+ - The `Quota` column counts attempts whose metadata looks quota-exhausted (a quota failure class, a `quota` flag, or text such as `rate limit` or `HTTP 429`). It is a count only. Quota is not an `onError` class, and the column does not choose a route. Walks a role opted into are listed under Route switches when the store has `routing.route_switched` events (`from`, `to`, `reason`, optional `effort`, `stepId`).
3485
3485
  - The text output does not list the sources, and prints `no routing records in telemetry` when no source holds a record. The Rwk% column counts records with `transitions` greater than 0, which Runtime records never set.
3486
- - JSON keys: `file` (the telemetry path, also when the Runtime store was read), `sources` (without `--file`; the same shape as in `kxm improve`), `configurations` (per behavioral hash for v1 records; `totalCostUsd` is `null` when any record lacks a cost, and `missingCostRuns` counts those records), `report` (`schema`, `generatedAt`, `totalAttempts`, `rows`).
3486
+ - JSON keys: `file` (the telemetry path, also when the Runtime store was read), `sources` (without `--file`; the same shape as in `kxm improve`), `configurations` (per behavioral hash for v1 records; `totalCostUsd` is `null` when any record lacks a cost, and `missingCostRuns` counts those records), `report` (`schema`, `generatedAt`, `totalAttempts`, `rows`, and `routeSwitches` when the store recorded any).
3487
3487
 
3488
3488
  With no routing records yet:
3489
3489
 
@@ -422,7 +422,7 @@ bytes.
422
422
  | `thinking` | String, 1 to 64 characters | Optional | Recorded on the route |
423
423
  | `tags`, `capabilities` | Unique identifiers, at most 32 | Optional | Selector tags |
424
424
  | `priority` | Integer, -10,000 to 10,000 | Optional | Recorded on the route |
425
- | `fallbacks` | Up to 8 `profile`, `tag`, or `provider`+`model` objects | Optional | Reference check |
425
+ | `fallbacks` | Up to 8 `profile`, `tag` (optional `capabilities`), or `provider`+`model` objects | Optional | The opt-in walk expands each roster entry one level |
426
426
  | `limits.contextTokens`, `limits.outputTokens` | Integer, at least 1 | Optional | Recorded on the route |
427
427
  | `limits.timeoutMs` | Integer, 0 to 31,536,000,000 | Optional | Recorded on the route |
428
428
 
@@ -917,9 +917,9 @@ global one with the same id.
917
917
  | `extends` | Identifier of another role in the same project | Optional | Refused when the chain cycles |
918
918
  | `roster[].effort` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, or `max` | Optional | Must be inside the harness ceiling when set |
919
919
  | `roster[].mode` | `headless`, `interactive`, or `either` | Optional | Recorded on the entry |
920
- | `policy.fallback.onError` | Unique `rate_limit`, `transport`, `provider_unavailable` | Optional | Recorded on the role |
921
- | `policy.fallback.maxSwitches` | Integer, at least 0 | Optional | Recorded on the role |
922
- | `policy.fallback.revert` | `next_run` or `never` | Optional | Recorded on the role |
920
+ | `policy.fallback.onError` | Unique `rate_limit`, `transport`, `provider_unavailable`, `context_overflow` | Optional; empty or absent means no walk | The attempt runner, only for a listed class |
921
+ | `policy.fallback.maxSwitches` | Integer, at least 0 | Optional; 1 when `onError` is non-empty and this field is omitted | The attempt runner. `0` allows no switch |
922
+ | `policy.fallback.revert` | `next_run` or `never` | Optional; `next_run` | `next_run` starts the next run on the first entry. `never` keeps the route that succeeded for later steps in the same run |
923
923
  | `skills`, `tools`, `produces`, `consumes` | See `schemas/role.schema.json` | Optional | `kxm role` |
924
924
  | `policy.vendorIndependenceRequired`, `policy.maxTransitions`, `policy.requiresGateVerification` | Boolean, or a positive integer for `maxTransitions` | Optional | Recorded on the role |
925
925
 
@@ -929,6 +929,19 @@ from the agent's `role` roster and that route's `.kxm/models/<route-id>.yaml`,
929
929
  never from the agent file. The developer assignment runner reads
930
930
  `.kxm/roles/*.yaml` and `.kxm/models/*.yaml` at `refs/remotes/origin/main`.
931
931
 
932
+ When `policy.fallback.onError` lists a failure class, a failed attempt of that
933
+ class continues on the next admitted route before it settles. The chain is the
934
+ role roster (own entries, then `extends`), then one level of each route's
935
+ `fallbacks` selectors. Retired, disabled, and unhosted routes are skipped. A
936
+ live write step also requires `edit`, an audited writer profile, and a writer
937
+ roster binding. When `policy.vendorIndependenceRequired` is true, a later
938
+ route whose vendor matches `reviewer-arch` or `reviewer-cli` is skipped. The
939
+ engine appends `routing.route_switched` and logs `route_switch`. A bounded
940
+ redacted transcript from the failed attempt is appended to the next prompt and
941
+ is not stored on the event. Cancellation, policy refusal, authentication, an
942
+ unhosted model, a gate failure, tool policy, and admission errors never walk.
943
+ A role with an empty or absent `onError` list fails on the first route.
944
+
932
945
  ```yaml
933
946
  schema: kxm.role.v2
934
947
  id: writer
@@ -296,7 +296,13 @@ No product producer writes `metered` today. Subscription runs are `unmetered` be
296
296
 
297
297
  `kxm routing report` groups records by harness, model, effort and role. It ranks routes by quality first (Pass%, then Rwk%), then by cost per accepted attempt. Among routes of equal quality, a route with any unknown-cost attempt ranks after every route without one, because its cost is unknown. Its `$/Acc` prints `-` instead of a partial sum, and the `*` in the `Unk` column marks it. Read `Unm` and `Unk` before you trust `$/Acc`.
298
298
 
299
- The `Quota` column counts attempts whose metadata looks quota-exhausted. Nothing fails over on it. The report has no provider column, so the `Harness` column is what tells you native from Pi.
299
+ The `Quota` column counts attempts whose metadata looks quota-exhausted. The column does not choose a route, and quota is not an `onError` class. The report has no provider column, so the `Harness` column is what tells you native from Pi.
300
+
301
+ ### Mid-attempt fallback
302
+
303
+ A role opts in by listing classes on `policy.fallback.onError`: `rate_limit`, `transport`, `provider_unavailable`, and `context_overflow`. An empty or absent list fails the attempt on the first route. On a listed class the engine appends `routing.route_switched` (`from`, `to`, `reason`, and `effort` when the next entry or the failing attempt has one), logs `route_switch`, and invokes the producer again on the next admitted chain entry, at most `maxSwitches` times (default 1; explicit `0` walks nothing). The chain is roster order, then `extends`, then one level of each route's `fallbacks` selectors. A bounded redacted transcript is appended to the next prompt and is not written to the event log.
304
+
305
+ Cancellation, policy refusal, authentication, an unhosted model, a gate failure, tool policy, and admission errors never walk. `revert: next_run` (the default) starts the next run on the first entry. `revert: never` keeps the route that succeeded for later steps in the same run. `kxm routing report` and `kxm improve report` print a Route switches section when the event store has any. See [`.kxm/roles`](config-reference.md#kxmrolesroleyaml-kxmrolev2).
300
306
 
301
307
  ```bash
302
308
  kxm routing report
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextmind/kxm",
3
- "version": "0.7.149",
3
+ "version": "0.7.151",
4
4
  "description": "KXM local-first multi-agent orchestration and operator dashboard",
5
5
  "type": "module",
6
6
  "author": "KontextMind",
@@ -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.149",
5
+ "version": "0.7.151",
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",