@kontextmind/kxm 0.7.95 → 0.7.97

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.kxm/README.md +39 -9
  3. package/CHANGELOG.md +23 -1
  4. package/README.md +147 -257
  5. package/SECURITY.md +21 -12
  6. package/docs/README.md +133 -54
  7. package/docs/adr/ADR-0002-browser-automation-steel-doks.md +24 -18
  8. package/docs/adr/ADR-0003-sqlite-only-store.md +100 -0
  9. package/docs/adr/ADR-0004-edge-identity-authentik.md +99 -0
  10. package/docs/adr/README.md +33 -0
  11. package/docs/concepts/architecture.md +262 -0
  12. package/docs/concepts/data-and-storage.md +194 -0
  13. package/docs/concepts/trust-model.md +153 -0
  14. package/docs/contracts/README.md +22 -14
  15. package/docs/contracts/effects-and-recovery.md +3 -0
  16. package/docs/contracts/migration.md +2 -2
  17. package/docs/contracts/routing.md +6 -5
  18. package/docs/contributing/assignment-runner.md +388 -0
  19. package/docs/contributing/ci-and-release.md +231 -0
  20. package/docs/contributing/development.md +362 -0
  21. package/docs/contributing/harness-routing-internals.md +192 -0
  22. package/docs/{packages.md → contributing/packages.md} +13 -15
  23. package/docs/{skills → contributing}/repo-work-delivery.md +20 -21
  24. package/docs/contributing/test-matrix.md +208 -0
  25. package/docs/{tui-components.md → contributing/tui-components.md} +30 -22
  26. package/docs/contributing/writing-docs.md +340 -0
  27. package/docs/glossary.md +471 -0
  28. package/docs/guides/agent-skills.md +137 -0
  29. package/docs/guides/browser-automation.md +160 -0
  30. package/docs/guides/context-and-memory.md +352 -0
  31. package/docs/guides/continuous-improvement.md +228 -0
  32. package/docs/guides/governed-skills.md +173 -0
  33. package/docs/guides/nous-providers.md +186 -0
  34. package/docs/guides/peer-messaging.md +304 -0
  35. package/docs/guides/pi-workers.md +219 -0
  36. package/docs/guides/provenance-gates.md +313 -0
  37. package/docs/guides/webhook-workflows.md +399 -0
  38. package/docs/kb/how-credentials-retrieved-safely.md +38 -12
  39. package/docs/kb/how-to-capture-and-annotate-section.md +15 -13
  40. package/docs/kb/how-to-connect-playwright-to-steel.md +16 -11
  41. package/docs/kb/how-to-recover-expired-session-or-orphan.md +26 -16
  42. package/docs/kb/how-to-resume-after-mfa.md +19 -11
  43. package/docs/kb/how-to-take-over-session.md +17 -13
  44. package/docs/kb/why-authentication-disappeared.md +22 -14
  45. package/docs/kb/why-automation-opened-different-browser.md +23 -14
  46. package/docs/kb/why-session-viewer-cannot-control.md +13 -12
  47. package/docs/operations/backup-and-restore.md +248 -0
  48. package/docs/operations/deploy.md +307 -0
  49. package/docs/operations/monitoring.md +209 -0
  50. package/docs/operations/runtime-sync.md +192 -0
  51. package/docs/operations/troubleshooting.md +266 -0
  52. package/docs/operations/upgrade.md +124 -0
  53. package/docs/prompts/browser-annotate-feedback.md +7 -7
  54. package/docs/prompts/browser-diagnose-recover.md +11 -10
  55. package/docs/prompts/browser-explore.md +7 -7
  56. package/docs/prompts/browser-repro-fix.md +7 -7
  57. package/docs/prompts/browser-start.md +12 -11
  58. package/docs/prompts/browser-takeover.md +8 -8
  59. package/docs/{cli-reference.md → reference/cli-reference.md} +88 -46
  60. package/docs/{config-reference.md → reference/config-reference.md} +159 -148
  61. package/docs/reference/configuration.md +299 -0
  62. package/docs/reference/harness-routing.md +508 -0
  63. package/docs/reference/http-api.md +203 -0
  64. package/docs/reference/tools.md +370 -0
  65. package/docs/{workflow-guide.md → reference/workflow-catalog.md} +92 -153
  66. package/docs/reference/workflow-definitions.md +286 -0
  67. package/docs/start/first-workflow.md +287 -0
  68. package/docs/start/install.md +146 -0
  69. package/docs/start/quickstart-claude-code.md +405 -0
  70. package/docs/start/quickstart-pi.md +213 -0
  71. package/docs/templates/README.md +78 -73
  72. package/docs/templates/adr.md +13 -13
  73. package/docs/templates/architecture.md +55 -71
  74. package/docs/templates/bug-fix.md +13 -16
  75. package/docs/templates/feature.md +14 -19
  76. package/docs/templates/handoff.md +44 -46
  77. package/docs/templates/postmortem.md +30 -43
  78. package/docs/templates/research.md +15 -20
  79. package/docs/templates/review.md +49 -50
  80. package/docs/templates/runbook.md +38 -30
  81. package/docs/templates/test-plan.md +16 -23
  82. package/docs/templates/test-report.md +14 -17
  83. package/examples/README.md +9 -5
  84. package/examples/provenance-workflow.json +1 -1
  85. package/examples/webhook-workflows/jira-development.json +59 -0
  86. package/examples/webhook-workflows/jira-issue-updated.json +12 -0
  87. package/examples/workflow-signal.ts +4 -5
  88. package/package.json +1 -1
  89. package/packages/core/tui/README.md +1 -1
  90. package/plugins/kxm/.claude-plugin/plugin.json +1 -1
  91. package/plugins/kxm/README.md +31 -32
  92. package/plugins/kxm/dist/claude-hook.js +11 -1
  93. package/plugins/kxm/dist/cli.js +164 -79
  94. package/plugins/kxm/dist/client.js +3 -1
  95. package/plugins/kxm/dist/core.js +11 -1
  96. package/plugins/kxm/dist/extension.js +45 -13
  97. package/plugins/kxm/dist/mcp-server.js +20 -4
  98. package/plugins/kxm/dist/runtime-supervisor.js +1 -3
  99. package/plugins/kxm/dist/runtime.js +18 -4
  100. package/plugins/kxm/dist/server.js +115 -20
  101. package/plugins/kxm/package.json +1 -1
  102. package/plugins/kxm/skills/kxm/references/protocol.md +3 -1
  103. package/plugins/kxm/skills/kxm-browser-auth/SKILL.md +1 -1
  104. package/plugins/kxm/skills/kxm-browser-diagnostics/SKILL.md +5 -5
  105. package/plugins/kxm/skills/kxm-browser-explore/SKILL.md +2 -2
  106. package/plugins/kxm/skills/kxm-browser-session/SKILL.md +10 -13
  107. package/plugins/kxm/skills/kxm-browser-takeover/SKILL.md +1 -1
  108. package/plugins/kxm/skills/kxm-browser-verify/SKILL.md +1 -1
  109. package/plugins/kxm/skills/kxm-context-memory/SKILL.md +13 -4
  110. package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +3 -1
  111. package/plugins/kxm/skills/kxm-mind-setup/SKILL.md +2 -1
  112. package/plugins/kxm/skills/kxm-project-setup/SKILL.md +31 -54
  113. package/plugins/kxm/skills/kxm-projects/SKILL.md +1 -1
  114. package/plugins/kxm/skills/kxm-protocol/SKILL.md +1 -1
  115. package/plugins/kxm/skills/kxm-routing-improve/SKILL.md +15 -7
  116. package/plugins/kxm/skills/kxm-runs/SKILL.md +11 -5
  117. package/plugins/kxm/skills/kxm-session/SKILL.md +1 -1
  118. package/plugins/kxm/skills/kxm-tasks/SKILL.md +9 -7
  119. package/plugins/kxm/skills/kxm-workflow/SKILL.md +10 -2
  120. package/plugins/kxm/src/cli/system.ts +1 -1
  121. package/plugins/kxm/src/cli/workflows.ts +12 -7
  122. package/plugins/kxm/src/cli.ts +22 -8
  123. package/plugins/kxm/src/client.ts +4 -0
  124. package/plugins/kxm/src/commands.ts +23 -1
  125. package/plugins/kxm/src/extension.ts +20 -14
  126. package/plugins/kxm/src/github-watch.ts +8 -5
  127. package/plugins/kxm/src/hub-env.ts +19 -1
  128. package/plugins/kxm/src/hub.ts +105 -21
  129. package/plugins/kxm/src/improve-sources.ts +2 -7
  130. package/plugins/kxm/src/init-guide-setup.ts +1 -1
  131. package/plugins/kxm/src/mcp-server.ts +9 -2
  132. package/plugins/kxm/src/modes.ts +1 -1
  133. package/plugins/kxm/src/runtime-store.ts +23 -0
  134. package/plugins/kxm/src/workflow.ts +70 -1
  135. package/schemas/README.md +1 -1
  136. package/scripts/smoke-multi-pi.mjs +5 -1
  137. package/docs/agent-communication-envelopes-and-gates.md +0 -553
  138. package/docs/agent-skills.md +0 -198
  139. package/docs/architecture.md +0 -245
  140. package/docs/assignment-runner.md +0 -264
  141. package/docs/browser-automation.md +0 -139
  142. package/docs/configuration.md +0 -437
  143. package/docs/continuous-improvement.md +0 -226
  144. package/docs/getting-started.md +0 -277
  145. package/docs/harness-routing.md +0 -616
  146. package/docs/kb/qa-authentik-authentication.md +0 -97
  147. package/docs/kb/qa-extension-install-and-hub-bootstrap.md +0 -85
  148. package/docs/kb/qa-hub-on-a-public-host.md +0 -48
  149. package/docs/kb/qa-sqlite-vs-duckdb.md +0 -35
  150. package/docs/kb/qa-what-the-hub-stores.md +0 -64
  151. package/docs/kxm-handbook.md +0 -1181
  152. package/docs/operations.md +0 -510
  153. package/docs/operator-pi-packages.md +0 -67
  154. package/docs/provenance-gates.md +0 -295
  155. package/docs/skills.md +0 -47
  156. package/docs/test-matrix.md +0 -132
  157. package/docs/troubleshooting.md +0 -322
  158. package/docs/webhook-workflows.md +0 -240
@@ -0,0 +1,228 @@
1
+ # Continuous improvement
2
+
3
+ KXM turns every run into structured evidence, ranks what keeps going wrong across runs, and proposes fixes that a person reviews and applies through Git. This page is for leads and workflow owners who want workflows to get more reliable and cheaper over time. It covers capture, ranked signals, retrospectives, coded-repeat candidates, and the safeguards that keep learning from turning into unreviewed policy.
4
+
5
+ What sets this apart:
6
+
7
+ - **Disagreement is preserved.** Contradictions stay open until evidence resolves them; nothing flattens them into one answer.
8
+ - **Everything is a proposal.** Signals, retrospectives and candidates never change a gate, workflow, permission or skill on their own.
9
+ - **Ranking is deterministic and redacted.** The same journal gives the same order, and merge keys never carry raw summary text.
10
+
11
+ ## Before you begin
12
+
13
+ - The `kxm` CLI and a running [hub](../glossary.md#hub).
14
+ - For journal capture: a hub workflow run started by a signed webhook or `kxm workflow start`. See [Webhook workflows](webhook-workflows.md).
15
+ - For coded repeats: Runtime runs created with `kxm run` in a KXM project.
16
+
17
+ > [!IMPORTANT]
18
+ > The journal loop covers hub webhook runs only. Runtime runs (`kxm run`) have no journal: `kxm_workflow_record` answers `workflow_not_found` for a Runtime run id. Runtime learning comes from `kxm improve`, which reads settled attempts instead.
19
+
20
+ ## The learning loop
21
+
22
+ The flowchart shows the two loops and where a person decides.
23
+
24
+ ```mermaid
25
+ flowchart LR
26
+ subgraph HUB["Hub workflow runs"]
27
+ REC[Journal entries<br/>from agents and the hub] --> SIG[Ranked signals<br/>kxm_improvement_report]
28
+ REC --> RETRO[Retrospective<br/>per terminal run]
29
+ end
30
+ subgraph RT["Runtime runs"]
31
+ EVT[(Run event store<br/>settled attempts)] --> IMP[kxm improve report]
32
+ IMP --> CAND[Candidates<br/>with proposed diffs]
33
+ end
34
+ SIG --> REVIEW{Human review}
35
+ RETRO --> REVIEW
36
+ CAND --> REVIEW
37
+ REVIEW -- reviewed PR --> CHANGE[Gates, workflows,<br/>skills, docs, memory]
38
+ CHANGE -- next runs --> REC
39
+ CHANGE -- next runs --> EVT
40
+ ```
41
+
42
+ ## Capture: record journal entries
43
+
44
+ Record entries while the run happens, not only at the end. Only the run's assigned coordinator can write its journal. Agents call `kxm_workflow_record`. The `kxm workflow record` CLI does the same from a shell; it connects as `KXM_AGENT_NAME` (default `cli-<pid>`), so it succeeds only under the coordinator's identity.
45
+
46
+ | Category | Record it when |
47
+ |---|---|
48
+ | `plan` | You decide how the work will run and who owns it, before implementation |
49
+ | `decision` | You pick an option; name the alternatives and why |
50
+ | `contradiction` | Agents, tests, docs or observed behavior disagree |
51
+ | `error` | A stage, tool, gate, integration or assumption fails |
52
+ | `lesson` | Evidence supports a reusable conclusion (evidence required) |
53
+ | `observation` | Something notable happened, without a causal claim |
54
+ | `hypothesis` | You make a falsifiable claim; keep it when it is disproved |
55
+ | `experiment` | You try something; record the outcome, including failure |
56
+ | `state-change` | An authoritative project fact changed |
57
+ | `skill-candidate` | A procedure worked and is backed by run or receipt evidence (evidence required) |
58
+
59
+ Each entry has an area (`harness`, `gates`, `implementation`, `workflow`, `documentation`, `security` or `other`), a severity (`info`, `warning` or `error`), a summary of at most 1,000 characters, optional details, up to 32 evidence strings and up to 16 related entries from the same run.
60
+
61
+ Pass `stageId` (`--stage-id` on the CLI) to bind an entry to a stage. The hub, never the caller, derives the attempt: the current attempt for an in-progress or waiting stage, the last attempt consumed for a finished stage, and none for a stage that has not run. When the stage declares an area, `area` may be omitted.
62
+
63
+ ```bash
64
+ kxm workflow record <run-id> lesson "A flaky test hid a race in the cache" \
65
+ --stage-id verify --severity warning --evidence https://ci.example.com/run/42
66
+ ```
67
+
68
+ | Refusal | Cause |
69
+ |---|---|
70
+ | `invalid_improvement_area` | No `area`, and no `stageId` whose stage declares one |
71
+ | `invalid_journal_relation` | The `stageId` or a related entry is not part of this run |
72
+ | `journal_evidence_required` | A `lesson` or `skill-candidate` without evidence |
73
+ | `workflow_forbidden` | The caller is not the run's coordinator |
74
+ | `workflow_not_found` | The id is not a hub workflow run, for example a `kxm run` id |
75
+
76
+ ### Entries KXM writes for you
77
+
78
+ You do not need to record these; each is bound to its stage and attempt where one applies:
79
+
80
+ - The hub records checkpoint warnings and failures, typed stage transitions, transition-budget exhaustion, external-wait timeouts, coordinator prompt expiry, premature coordinator settlement, and degraded-quorum approvals and their use.
81
+ - The Pi extension records failed tool results and failed turns while a webhook workflow is active, as an allowlisted diagnostic class rather than tool output.
82
+ - A supervised Pi worker records the reason each time it recovers.
83
+
84
+ Agents still record semantic failures: a false assumption, a rejected design, a flaky result or an integration mismatch.
85
+
86
+ Never put secrets or unneeded prompt text in the journal. Cite durable references instead: test names, commits, pull requests, check runs, issues or documentation paths. Adding a lowercase `class:<name>` to an entry's evidence lets identical failures merge across runs.
87
+
88
+ ### Governed promotion of journal entries
89
+
90
+ `skill-candidate`, `hypothesis` and `experiment` entries start `proposed`. A hub administrator decides them once, append-only, through `POST /v1/journal/<entry-id>/promotion` with `to` (`approved`, `rejected` or `quarantined`), at least one evidence reference and a reason. The decider is recorded as `kxm-admin` and can never be the entry's author, and a decided entry never reopens. This changes the entry's learning state only; it never changes a gate, a workflow or a permission. See [HTTP API](../reference/http-api.md).
91
+
92
+ ## Signals: rank what recurs across runs
93
+
94
+ `kxm_improvement_report` answers for the agent's project with three fields: `reports`, per-area counts with each area's ten most severe errors, contradictions, lessons and skill candidates; `signals`, the top 20 recurring problems; and `entries`, the number of journal entries read. Review the top signals weekly.
95
+
96
+ Only errors, open contradictions (not yet answered by a related decision or lesson), lessons, and skill candidates still `proposed` count. Entries merge into one signal when they share a key, tried in this order:
97
+
98
+ 1. An evidence class, `class:<name>`, within the same category.
99
+ 2. For errors, the workflow definition and stage.
100
+ 3. The summary after redaction and normalization: ids, timestamps, hex strings and numbers are folded, so the same failure in two runs keys the same.
101
+
102
+ Each signal keeps up to 16 run ids and entry ids and a redacted summary of its latest entry. It is scored as:
103
+
104
+ ```text
105
+ priority = frequency × severity weight × workflow cost × confidence
106
+ ```
107
+
108
+ | Factor | Meaning |
109
+ |---|---|
110
+ | Frequency | Distinct runs, counted over the runs the hub still retains |
111
+ | Severity weight | 3 for `error`, 2 for `warning`, 1 for `info`, from the most severe entry |
112
+ | Workflow cost | Mean run attempts (stage attempts plus transitions) over known runs; 1 with `costBasis: "unknown"`. Not dollars |
113
+ | Confidence | 0.5 plus half the share of the signal's entries that cite evidence |
114
+
115
+ Security signals (area `security`, or class `invalid_auth`, `invalid_identity` or `signal_mismatch`) rank ahead of every priority. Other ties break on frequency, then key, never on insertion order. There is no data-loss override, because no deterministic data-loss marker exists; review data-loss risk by hand.
116
+
117
+ > [!NOTE]
118
+ > The hub purges terminal runs and their journal 7 days after they end, so frequency only counts recent runs. Export accepted decisions and lessons to version-controlled docs or [Git memory](context-and-memory.md#author-git-memory) if they must outlive that window.
119
+
120
+ ## Retrospectives: one run, reviewed
121
+
122
+ When a hub run completes or fails, the hub writes a bounded retrospective to `.kxm/assets/retrospectives/<run-id>.json` and `<run-id>.md`. It writes them again when a journal entry arrives or a promotion is decided after the run ended. Regenerate one from the local store, or from an offline snapshot:
123
+
124
+ ```bash
125
+ kxm workflow export <run-id>
126
+ kxm workflow export <run-id> --input snapshot.json
127
+ ```
128
+
129
+ A retrospective holds the stage timeline, counts by category, area and class, open contradictions, decisions, and the last 500 redacted entries. Two fields drive review:
130
+
131
+ - `recurringErrorClasses` counts `error` entries only, by evidence class.
132
+ - `proposedImprovements` holds up to 12 of the run's error and lesson entries, merged and ranked like the signals above, each with a success measure that names its signal key.
133
+
134
+ Runs with peer-evidence policies add a metadata-only `evidenceAudit`: configured and effective producer minimums, eligible producers, verified message and producer ids, request and reply hashes, and admin degradation approvals. It never copies message bodies, and its hashes are provenance, not proof that a peer was right. Every file stays `reviewDecision: "proposed"`; export never edits a workflow or weakens a gate.
135
+
136
+ ## Coded repeats (`kxm improve`)
137
+
138
+ `kxm improve` (the same as `kxm improve report`) finds Runtime agent steps that a script, test or workflow `gate` could do as well as a model. It proposes; it never applies.
139
+
140
+ ```bash
141
+ kxm improve report --dry-run
142
+ ```
143
+
144
+ Expected output, in a directory that is not a KXM project:
145
+
146
+ ```text
147
+ Sources:
148
+ telemetry /work/demo/.kxm/logs/telemetry.jsonl (exists=false, records=0, duplicatesDropped=0)
149
+ Runtime store not read: no KXM project at /work/demo
150
+ ```
151
+
152
+ ### Sources
153
+
154
+ Inside a KXM project the command reads the project's Runtime event store, `<state>/runtime/projects/<key>/run-events.db`, then `.kxm/logs/telemetry.jsonl`. The key comes from the checkout's real path, so each checkout and worktree has its own store. The store is opened read-only for one query; `kxm improve` never creates, writes or migrates it. A telemetry record whose `attemptId` the store already supplied is dropped. `--file <path>` reads only that file.
155
+
156
+ The output starts with a `sources` block: each source's path, whether it exists, and its `records`, `skippedInvalid`, `excludedSimulated`, `undecided` and `duplicatesDropped` counts. An unreadable store stops the command with `improve_source_unreadable` and exit 1.
157
+
158
+ ### Groups and outcomes
159
+
160
+ Records group by workflow, step, agent role and ask. The ask digest covers the workflow, step, step kind, agent, instructions, outcomes and required evidence keys, so one step keeps one digest across runs. No prompt text is read or stored.
161
+
162
+ Outcomes are resolved from the event log when the report runs and never written back. A back edge is `blocked`; a producer error, an undeclared outcome or a failing terminal is `failed`; a later entry into the same step makes an attempt `reworked`; a completed run makes it `accepted`; a failed run makes it `failed`. Cancelled and still-running runs stay undecided and are left out of the pass rate. Simulated attempts are excluded and counted.
163
+
164
+ ### Candidacy
165
+
166
+ A group becomes a coded-repeat candidate only when all three hold:
167
+
168
+ - The same objective was decided in at least 2 runs (`askRecurrence`).
169
+ - At least 0.75 of its decided attempts were accepted (`verifyPassRate`). An attempt superseded by a retry of the same step never counts as a pass.
170
+ - Its step writes no repository (`writesRepository`).
171
+
172
+ A group that passes the rate but misses reports `excludedReason`: `writes-repository` or `ask-not-repeated`. `weightedRecurrence` weighs each record by `2^(-age / improvement.telemetryHalfLifeDays)`, 14 days by default. It orders rows and never decides candidacy.
173
+
174
+ ### Outputs and promotion readiness
175
+
176
+ Each candidate is a `kxm.candidate.v1` JSON file plus a proposed diff under `.kxm/candidates/` (or `--out-dir`), and the report is saved under `.kxm/assets/improvements/`. `--dry-run` writes neither. The step and role names pick the template: a verify, gate, test, check or lint step proposes a `.kxm/gates.yaml` command; a plan, review or repro step proposes a governed skill; any other step proposes a `kind: gate` step that runs `scripts/<step>.mjs`, which you write. Diffs contain placeholder hunks.
177
+
178
+ `promotion[]` reports readiness under `improvement.promotionPolicy` (see [Configuration file reference](../reference/config-reference.md)):
179
+
180
+ | Policy | Ready for review when |
181
+ |---|---|
182
+ | `manual_pr` (default) | Always; you review and apply the diff in a PR |
183
+ | `critic_quorum` | Two distinct critic receipts are cited; `kxm improve` cites none, so never |
184
+ | `auto_threshold` | Distinct runs, accepted share and mean recorded cost reach `improvement.autoThreshold`; a group with no recorded cost is never ready |
185
+
186
+ No policy authorizes anything. Every policy ends at an operator PR, activation is a reviewed Git change for future runs, and telemetry cannot grant a tool or skip a gate.
187
+
188
+ `kxm routing report` reads the same sources to compare verified completion, cost and rework per model route. Use it next to `kxm improve` when a repeat is also expensive. See [Harness routing](../reference/harness-routing.md).
189
+
190
+ ## Review cadence
191
+
192
+ - **Per run.** Read the retrospective. Group contributing causes, then name an owner and a measurable success condition for each proposed improvement.
193
+ - **Weekly.** Call `kxm_improvement_report` and `kxm improve report`. Check that each merge groups entries that belong together, and pick a few items to trial.
194
+ - **Per release.** For each chosen improvement:
195
+ 1. State the problem and link its evidence.
196
+ 2. Name what it changes: harness, gates, implementation guidance, workflow, docs or security policy.
197
+ 3. Define the expected outcome and a leading indicator.
198
+ 4. Add or update tests before you change enforcement.
199
+ 5. Trial it on a bounded workflow or repository.
200
+ 6. Compare failure rate, cycle time, manual intervention and escaped defects with the baseline.
201
+ 7. Adopt, revise or roll it back, and record the decision in a later run's journal.
202
+
203
+ ## Governance safeguards
204
+
205
+ - Journal content is evidence, not executable policy.
206
+ - Candidates are proposals. Readiness never authorizes, and no `improvement.*` value activates anything.
207
+ - An agent may propose a gate change but cannot silently weaken a required gate.
208
+ - A peer-quorum reduction must be declared by policy and approved by an administrator for the current attempt, and it is recorded as degraded, not as normal success.
209
+ - Contradictions stay open until evidence resolves them; synthesis must not erase minority risks.
210
+ - Changes to permissions, secrets, merge policy or external side effects need human or repository-authorized approval.
211
+ - Reports are project-scoped. Protect the hub database: the journal can reveal sensitive engineering context.
212
+
213
+ ## Troubleshooting
214
+
215
+ | Symptom | Cause | Fix |
216
+ |---|---|---|
217
+ | `kxm_workflow_record` answers `workflow_not_found` | The id belongs to a `kxm run` Runtime run | Use `kxm improve` for Runtime learning |
218
+ | `kxm improve` reads 0 records | Not inside a KXM project, no settled Runtime attempts, or only simulated drives | Check the `sources` block and `excludedSimulated` |
219
+ | `kxm improve` exits 1 with `improve_source_unreadable` | The event store is locked or damaged | Retry, then inspect the path it names |
220
+ | A signal merges unrelated entries | They share a summary shape or a class | Add distinct `class:<name>` evidence |
221
+ | A recurring problem vanished from signals | Its runs were purged after 7 days, or its entry was decided | Export lessons to Git before the window closes |
222
+
223
+ ## Next steps
224
+
225
+ - Promote a working procedure into a reusable skill: [Governed skills](governed-skills.md)
226
+ - Keep durable lessons where agents read them: [Context and memory](context-and-memory.md)
227
+ - Require independent evidence before a stage passes: [Provenance gates](provenance-gates.md)
228
+ - Every flag and output key: [CLI reference](../reference/cli-reference.md)
@@ -0,0 +1,173 @@
1
+ # Governed skills
2
+
3
+ Turn a procedure that worked in a run into a reusable skill your agents can rely on, without letting run-time experience rewrite agent behavior on its own. You submit a candidate, record the results of four protected evaluations, and promote it through a reviewed pull request. Promoted skills are hash-pinned and immutable, and they inform agents but never grant a tool or a permission.
4
+
5
+ This page covers the `kxm skills` lifecycle. The skills that ship with the plugin are a different thing; see [Agent skills](agent-skills.md).
6
+
7
+ ## Before you begin
8
+
9
+ - The `kxm` CLI. Run the commands from the repository root: skills live in `.kxm/skills/` under `KXM_WORKDIR` or the current directory. No hub is needed.
10
+ - At least one source for the candidate: a workflow run id, a journal entry id or an evidence receipt.
11
+ - Two identities: the author who creates the candidate, and a different person who decides its promotion.
12
+
13
+ ## The lifecycle
14
+
15
+ A candidate stays a candidate while evaluations are recorded, and leaves that state only by promotion, quarantine or rejection.
16
+
17
+ ```mermaid
18
+ stateDiagram-v2
19
+ [*] --> candidate: kxm skills create
20
+ candidate --> candidate: record a static-review, sandbox,<br/>functional or safety result
21
+ candidate --> quarantined: functional or safety fails
22
+ candidate --> promoted: kxm skills promote<br/>(latest result of all four passed)
23
+ candidate --> rejected: kxm skills reject
24
+ quarantined --> [*]
25
+ rejected --> [*]
26
+ note right of promoted
27
+ Hash-pinned and immutable.
28
+ A behavior change is a new
29
+ candidate with --supersedes.
30
+ end note
31
+ ```
32
+
33
+ Evaluations can be recorded in any order, and a later result for the same kind replaces the earlier one. A failed `static-review` or `sandbox` result leaves the candidate in place so you can fix and re-evaluate. A failed `functional` or `safety` result quarantines it at once.
34
+
35
+ ## Where skills live
36
+
37
+ | Path under `.kxm/skills/` | Holds |
38
+ |---|---|
39
+ | `candidates/<id>/` | `SKILL.md` and `metadata.json` for each candidate |
40
+ | `promoted/<id>/` | Copies of promoted candidates |
41
+ | `quarantineds/<id>/` | Quarantined candidates (the code spells this directory name with a trailing `s`) |
42
+ | `rejected/<id>/` | Rejected candidates |
43
+ | `history/<id>.jsonl` | Append-only audit trail: creation, evaluations and decisions, the last 500 records |
44
+ | `patches/<id>.patch` | The diff that promotion emits for review |
45
+
46
+ Skill ids are content-addressed: `<slug>.<first 12 hex characters of the content hash>`. Changed behavior means changed content, which means a new id. Submitting identical content again is refused.
47
+
48
+ ## Create a candidate
49
+
50
+ Write the procedure as a Markdown file. KXM adds `name` and `description` front matter when the file has none.
51
+
52
+ `flaky.md`:
53
+
54
+ ```markdown
55
+ # Triage a flaky test
56
+
57
+ 1. Re-run the failing test three times in isolation.
58
+ 2. Record each result as journal evidence.
59
+ ```
60
+
61
+ ```bash
62
+ kxm skills create --file flaky.md --name "Triage flaky test" \
63
+ --description "Isolate and classify a flaky test before changing code" \
64
+ --created-by agent-a --harness pi --models openrouter/qwen/qwen3-coder-plus \
65
+ --journal journal_abc
66
+ ```
67
+
68
+ Expected output:
69
+
70
+ ```text
71
+ created skill candidate triage-flaky-test.7f0864c17a97
72
+ ```
73
+
74
+ The candidate must cite at least one source (`--run`, `--journal` or `--receipt`), name its harness, and list 1 to 16 compatible models. Names are at most 64 characters and content at most 32,000. Secrets are redacted from the content and description before anything is written.
75
+
76
+ ## Record evaluations
77
+
78
+ Each evaluation records a verdict that you or your evaluator produced. KXM does not run the skill, and it provides no sandbox; `sandbox` names the check you performed, it does not create one.
79
+
80
+ ```bash
81
+ kxm skills evaluate triage-flaky-test.7f0864c17a97 --kind static-review --evaluator review-checklist-v1
82
+ kxm skills evaluate triage-flaky-test.7f0864c17a97 --kind sandbox --evaluator scratch-repo-v1
83
+ kxm skills evaluate triage-flaky-test.7f0864c17a97 --kind functional --evaluator flaky-suite-v2 --score 0.92
84
+ kxm skills evaluate triage-flaky-test.7f0864c17a97 --kind safety --evaluator safety-review-v1
85
+ ```
86
+
87
+ Add `--fail` to record a failure, and `--details` for up to 2,000 characters of redacted notes. A failed `functional` or `safety` evaluation prints `(candidate quarantined)` and records the quarantine decision under the evaluator's name. The `optimization` kind is refused: optimization evaluations are disabled and the CLI has no switch to enable them.
88
+
89
+ ## Promote through Git
90
+
91
+ Promotion needs the latest result of all four kinds to be a pass, at least one durable evidence reference, a decider who is not the author, and content that still matches its hash. Preview it first:
92
+
93
+ ```bash
94
+ kxm skills promote triage-flaky-test.7f0864c17a97 --decided-by reviewer-b --evidence review:pr-31 --dry-run
95
+ ```
96
+
97
+ Expected output:
98
+
99
+ ```text
100
+ dry run: promote skill triage-flaky-test.7f0864c17a97
101
+ would write /work/demo/.kxm/skills/promoted/triage-flaky-test.7f0864c17a97/SKILL.md
102
+ would write /work/demo/.kxm/skills/promoted/triage-flaky-test.7f0864c17a97/metadata.json
103
+ would write /work/demo/.kxm/skills/patches/triage-flaky-test.7f0864c17a97.patch
104
+ would write /work/demo/.kxm/skills/history/triage-flaky-test.7f0864c17a97.jsonl
105
+ ```
106
+
107
+ Run it without `--dry-run`, then land the result through review:
108
+
109
+ 1. Open a pull request with the new `promoted/<id>/` directory. `patches/<id>.patch` is a new-file diff of exactly those two files, for reviewers who prefer a patch.
110
+ 2. Remove the candidate copy in the same pull request. Promotion copies the candidate; it does not move it, so `kxm skills list --state candidate` still shows it.
111
+ 3. Merge. From then on the skill is immutable.
112
+
113
+ > [!IMPORTANT]
114
+ > Promotion writes into your working tree immediately. A hub started from this checkout can serve the promoted skill in `kxm context get` packets as soon as the files exist and verify. Runtime agents receive it only after the files are committed and clean. See [Context for Runtime agents](context-and-memory.md#context-for-runtime-agents).
115
+
116
+ ## Reject a candidate
117
+
118
+ ```bash
119
+ kxm skills reject bump-deps.489552361ce3 --decided-by reviewer-b --reason "Duplicates an existing gate"
120
+ ```
121
+
122
+ Rejection moves the candidate to `rejected/` and keeps its history for future learning. It works on candidates only: a quarantined skill cannot be rejected from the CLI, so quarantine is terminal there. Remove a quarantined directory by pull request if you no longer want it.
123
+
124
+ ## Verify integrity
125
+
126
+ `kxm skills verify` recomputes the content hash and checks that the front matter has a `name` and a `description`. It checks promoted skills by default; pass `--state` for another state.
127
+
128
+ ```bash
129
+ kxm skills verify triage-flaky-test.7f0864c17a97
130
+ ```
131
+
132
+ Expected output:
133
+
134
+ ```text
135
+ skill triage-flaky-test.7f0864c17a97 integrity verified
136
+ ```
137
+
138
+ An out-of-band edit fails with `content does not match its pinned hash; promoted skills are immutable and require a new candidate/eval cycle`. The hub and the Runtime run the same check. The hub leaves a failing skill out of packets; the Runtime leaves it out and records a `dispatch_context_skill_unverified:<id>` gap.
139
+
140
+ ## Supersede a promoted skill
141
+
142
+ To change a promoted skill, create a new candidate from the edited content with `--supersedes <old-id>`, and take it through the whole lifecycle. The link is recorded in the new candidate's metadata and history. Nothing retires the old skill automatically: remove its `promoted/` directory in the pull request that adds the new one.
143
+
144
+ ## How promoted skills reach agents
145
+
146
+ - **Hub packets.** Each promoted skill that verifies becomes a `skill` item at `instruction` authority and `verified` confidence. Its summary is `<name>: <description>` and its source is `skill:<id>@<sha256>`. Only roles that request the `skill` kind receive it, which by default means `implementer`.
147
+ - **Runtime dispatch.** The same item, only when the promoted files are committed and clean, listed under **Active Skills** in the agent's prompt.
148
+ - **What is delivered.** The name, description and pinned hash reference, not the full `SKILL.md` body.
149
+
150
+ Skill text may shape behavior. It never grants a tool, a permission or an approval.
151
+
152
+ ## Other sources of candidates
153
+
154
+ - A journal `skill-candidate` entry records that a procedure worked. Its own approval lifecycle is separate: approving the entry does not create a governed skill. See [Continuous improvement](continuous-improvement.md#governed-promotion-of-journal-entries).
155
+ - `kxm improve` can propose a governed skill for a repeated planning, review or repro step. Its diff is a starting point; submit the result with `kxm skills create`.
156
+
157
+ ## Troubleshooting
158
+
159
+ | Message | Cause | Fix |
160
+ |---|---|---|
161
+ | `a skill candidate must reference at least one source run, journal entry, or evidence receipt` | No `--run`, `--journal` or `--receipt` | Cite the run or entry the skill came from |
162
+ | `identical candidate <id> already exists` | The same content was submitted before | Change the content, or use the existing id |
163
+ | `promotion requires passing <kinds> evaluations` | A kind has no result, or its latest result failed | Record passing evaluations for the listed kinds |
164
+ | `the author of a skill candidate cannot promote it` | `--decided-by` equals `--created-by` | Have a different person decide |
165
+ | `skill <id> not found in candidate` | The skill is quarantined, rejected or already removed | Check `kxm skills list --state <state>` |
166
+ | `optimization evaluations are disabled` | `--kind optimization` | Use one of the four protected kinds |
167
+
168
+ ## Next steps
169
+
170
+ - See how skills sit beside memory and state in a packet: [Context and memory](context-and-memory.md)
171
+ - Find which steps keep repeating: [Continuous improvement](continuous-improvement.md#coded-repeats-kxm-improve)
172
+ - The skills that ship with KXM: [Agent skills](agent-skills.md)
173
+ - Every flag: [CLI reference](../reference/cli-reference.md)
@@ -0,0 +1,186 @@
1
+ # Nous providers
2
+
3
+ Reach Nous Research models from Pi through one of three opt-in provider routes, and check that KXM will actually dispatch them before you depend on one. This page is for operators who run Pi agents and want Nous Portal, the Nous direct API, or a Hermes subscription proxy. None of these routes is a writer route, and none is enabled by default.
4
+
5
+ Nous routes are Pi *providers*, not a separate harness: there is no Nous `kxm agent worker`, and Pi stays the only long-lived worker. See [Supervised Pi workers](pi-workers.md).
6
+
7
+ ## Before you begin
8
+
9
+ - Pi installed. For the `nous/` and `nous-proxy/` routes, Pi must also load the KXM extension. See [Install](../start/install.md).
10
+ - A Nous Portal subscription or a Nous API key.
11
+ - For the proxy route only: the Hermes CLI, which you install and log in to yourself. KXM never installs it, logs in, starts the proxy, or makes paid requests for you.
12
+
13
+ ## Choose a route
14
+
15
+ | Route | Model ids | Registered by | Authenticates with |
16
+ |---|---|---|---|
17
+ | Nous Portal | `nous-portal/<model>` | The third-party Pi package `@jayteelabs/pi-nous-portal-provider` | Pi `/login`, or `NOUS_API_KEY` |
18
+ | Direct API | `nous/<model>` | The KXM Pi extension, when `KXM_NOUS_PROVIDERS` includes `direct` | `NOUS_API_KEY` only |
19
+ | Hermes proxy | `nous-proxy/<model>` | The KXM Pi extension, when `KXM_NOUS_PROVIDERS` includes `proxy` | Your Hermes login, through a loopback proxy |
20
+
21
+ The Portal route bills your Portal account, not OpenRouter. With `KXM_NOUS_PROVIDERS` unset, the KXM extension starts synchronously and offline: no fetch, no provider registration, no notice.
22
+
23
+ ## Set up Nous Portal
24
+
25
+ 1. Install the provider package into Pi:
26
+
27
+ ```bash
28
+ pi install npm:@jayteelabs/pi-nous-portal-provider
29
+ ```
30
+
31
+ 2. Log in. In Pi, run `/login`, choose subscription or API key, then Nous Research Portal. Alternatively, export `NOUS_API_KEY` in the shell or supervisor that starts Pi.
32
+
33
+ In Pi:
34
+
35
+ ```text
36
+ /login
37
+ ```
38
+
39
+ 3. Optionally override the endpoints. The package documents `NOUS_PORTAL_BASE_URL` (default `https://portal.nousresearch.com`) and `NOUS_INFERENCE_BASE_URL` (default `https://inference-api.nousresearch.com/v1`).
40
+
41
+ ## Verify the Portal route
42
+
43
+ Check both that Pi lists the models and that Pi reports the provider ready. KXM trusts only the second check.
44
+
45
+ ```bash
46
+ # Which Portal model ids does this install expose?
47
+ pi --list-models nous-portal
48
+ # Is the provider authenticated? KXM runs this same check before it dispatches.
49
+ pi auth check --provider nous-portal --json
50
+ ```
51
+
52
+ The route is usable only when `status` is `ready`. Model ids change: the reviewed experiment example is `nous-portal/tencent/hy4-preview`, and some installs list `tencent/hy3-preview` instead. Use the ids your install prints.
53
+
54
+ > [!IMPORTANT]
55
+ > In some installs `pi auth check --provider nous-portal` reports `provider_not_found` even though `pi --list-models` lists Portal models:
56
+ >
57
+ > `{"status":"not_ready","provider":"nous-portal","reason":"provider_not_found"}`
58
+ >
59
+ > KXM treats that answer as not authenticated. `kxm harness list` shows the Pi route as not authenticated, and the Runtime refuses to dispatch it. There is no override: fix the Pi install until the check reports `ready`.
60
+
61
+ Run a Portal model interactively:
62
+
63
+ ```bash
64
+ pi --model nous-portal/<model-id>
65
+ ```
66
+
67
+ ## Enable the direct API
68
+
69
+ 1. Export `NOUS_API_KEY` in the shell or supervisor that starts Pi. The direct route reads only this variable; it does not use credentials stored by Pi `/login`.
70
+ 2. Export `KXM_NOUS_PROVIDERS=direct`.
71
+ 3. Optionally point `KXM_NOUS_CATALOG_FILE` at a dated price pin. See [Pin a price catalog](#pin-a-price-catalog).
72
+ 4. Start Pi. Models appear as `nous/<id>` only when their capacity and verified numeric rates are known, from the live `/v1/models` catalog or from the pin.
73
+
74
+ ```bash
75
+ export NOUS_API_KEY="replace-with-nous-api-key"
76
+ export KXM_NOUS_PROVIDERS=direct
77
+ pi --list-models nous/
78
+ ```
79
+
80
+ ## Enable the Hermes proxy
81
+
82
+ 1. Install Hermes if it is missing, then log in: `hermes login --provider nous`. Newer Hermes docs also mention `hermes setup --portal`; that flow is not verified on every CLI.
83
+ 2. Start the proxy with `hermes proxy start`, and check it with `hermes proxy status`. The default base URL is `http://127.0.0.1:8645/v1`.
84
+ 3. Export `KXM_NOUS_PROVIDERS=proxy`, or `direct,proxy` for both routes.
85
+ 4. Start Pi. Models appear as `nous-proxy/<id>`, with `subscription proxy, market ref` in their display name.
86
+
87
+ If the proxy is down, the extension tells you to run `hermes proxy start`. If it answers unauthorized, the extension tells you to log in again.
88
+
89
+ ## Environment variables
90
+
91
+ | Variable | Default | Effect |
92
+ |---|---|---|
93
+ | `KXM_NOUS_PROVIDERS` | unset (off) | Comma list of `direct` and `proxy`. An unknown token fails closed: nothing is registered |
94
+ | `NOUS_API_KEY` | unset | API key for the direct route; also accepted by the Portal package |
95
+ | `KXM_NOUS_PROXY_URL` | `http://127.0.0.1:8645/v1` | Proxy base URL. Must be loopback (`127.0.0.1`, `localhost` or `::1`) over `http` or `https`; anything else fails closed |
96
+ | `KXM_NOUS_DISCOVERY_TIMEOUT_MS` | `5000` | Timeout for the `GET /v1/models` discovery request. Must be a positive number |
97
+ | `KXM_NOUS_CATALOG_FILE` | unset | Path to a `kxm.nous-catalog.v1` price pin |
98
+ | `KXM_NOUS_MODELS_URL` | Nous public catalog | Catalog URL that `kxm models refresh` reads for the model inventory |
99
+
100
+ ## Pin a price catalog
101
+
102
+ A pin supplies capacity and rates when the live catalog is incomplete, so a model is registered with known prices instead of guessed ones.
103
+
104
+ ```json
105
+ {
106
+ "schema": "kxm.nous-catalog.v1",
107
+ "recordedAt": "2026-09-20T00:00:00.000Z",
108
+ "source": "Nous Portal pricing page, checked by the operator",
109
+ "units": "usd_per_million_tokens",
110
+ "hash": "sha256:<64 hex characters>",
111
+ "models": {
112
+ "<model-id>": {
113
+ "contextWindow": 131072,
114
+ "maxTokens": 8192,
115
+ "cost": { "input": 0.8, "output": 2.4, "cacheRead": 0.08, "cacheWrite": 0.8 },
116
+ "priceBasis": "list",
117
+ "billing": "metered",
118
+ "verified": true
119
+ }
120
+ }
121
+ }
122
+ ```
123
+
124
+ `priceBasis` is `list` or `upper-bound`, and `billing` is `metered`, `subscription` or `subscription_plus_usage`. A model may add `tiers`, each with `inputTokensAbove` and its own four rates; the highest rate per component becomes the price, labelled as an upper bound. `hash` is the SHA-256 of the canonical JSON (sorted keys, no whitespace) of `recordedAt`, `source`, `units` and `models`. Compute it with Node:
125
+
126
+ ```bash
127
+ node -e '
128
+ const { createHash } = require("node:crypto");
129
+ const pin = JSON.parse(require("node:fs").readFileSync(process.argv[1], "utf8"));
130
+ const canon = (v) => v === null || typeof v !== "object" ? JSON.stringify(v)
131
+ : Array.isArray(v) ? `[${v.map(canon).join(",")}]`
132
+ : `{${Object.keys(v).sort().map((k) => `${JSON.stringify(k)}:${canon(v[k])}`).join(",")}}`;
133
+ const { recordedAt, units, models } = pin;
134
+ const source = pin.source.trim();
135
+ console.log("sha256:" + createHash("sha256").update(canon({ recordedAt, source, units, models })).digest("hex"));
136
+ ' nous-pin.json
137
+ ```
138
+
139
+ The whole pin is ignored when its hash does not match, its units are missing, it is dated in the future, it is older than 30 days, or any model entry is invalid. An unverified zero rate makes an entry invalid; verified zeros are allowed.
140
+
141
+ ## How prices are read
142
+
143
+ From the public `GET https://inference-api.nousresearch.com/v1/models` catalog, KXM reads `context_length`, `top_provider.max_completion_tokens`, `architecture.input_modalities`, `supported_parameters` (`tools`, `reasoning`), and the `pricing.prompt`, `completion`, `input_cache_read` and `input_cache_write` per-token prices plus `pricing.overrides[]`. It converts them once to US dollars per million tokens. It never applies `pricing.original` or a blanket discount.
144
+
145
+ Incomplete or malformed live rates exclude the model rather than drop a costly tier or guess zero, unless a matching pin supplies verified rates and capacity. Context tiers collapse to the highest rate per component, and that upper bound is what Pi's cost calculation sees, so a price never underquotes at a tier threshold. Upper-bound estimates are labelled in `nous/*` and `nous-proxy/*` display names.
146
+
147
+ ## What has been verified
148
+
149
+ At the last compatibility check (2026-09-07), tests verified one streamed tool call with usage on `qwen/qwen3-coder-plus`, through both the direct API and an OAuth-backed Hermes proxy. Both reported usage.
150
+
151
+ Still unknown or unverified:
152
+
153
+ - How much included subscription quota a request consumes, and any extra billed amount.
154
+ - Every other model, and automatic auth refresh.
155
+ - Claude to Nous to Qwen: Nous documents native Messages support for `anthropic/*` only, and Qwen uses chat completions, so that path is unsupported.
156
+ - A mocked bearer token proves header support, not that OAuth credentials are interchangeable.
157
+
158
+ ## Admission and routing rules
159
+
160
+ A route that Pi can reach is not a route KXM will dispatch. Admission decides that, and it is a reviewed decision, not a configuration tweak.
161
+
162
+ - **No Nous route is a writer.** `nous-portal/tencent/hy4-preview` is a reviewed read-only experiment example, not a writer. Any other `nous-portal` writer route needs its own reviewed admission.
163
+ - **`nous/` and `nous-proxy/` carry no admission.** Registering them adds models to Pi's list; it grants no writer or router role, and the developer assignment helper does not allowlist them.
164
+ - **Native vendors stay in their own harness.** The Portal also hosts `anthropic/…`, `openai/…`, `x-ai/…` and `google/…` models. Those vendors have native harnesses, so use those instead of the aggregator copy. The Pi native-vendor brake reads the vendor segment, so it refuses `nous-portal/anthropic/…`, `nous-portal/x-ai/…` and the same ids under `nous/` and `nous-proxy/`, at dispatch and when a worker starts; see [What the brake refuses](../reference/harness-routing.md#what-the-brake-refuses).
165
+ - **Auth fails closed.** When `pi auth check` does not report `ready`, KXM refuses the route rather than billing another provider.
166
+ - **The product Runtime dispatches only admitted selectors**, listed under `admitted` in `.kxm/routes.yaml` and, when a role file exists, in that role's roster.
167
+
168
+ See [Harness routing](../reference/harness-routing.md#nous) for the full decision procedure.
169
+
170
+ ## Troubleshooting
171
+
172
+ | Symptom | Cause | Fix |
173
+ |---|---|---|
174
+ | No `nous/` models appear | `KXM_NOUS_PROVIDERS` is unset, `NOUS_API_KEY` is unset, or no model has verified rates | Export both, or add a valid price pin |
175
+ | Nothing registers and Pi shows an error | `KXM_NOUS_PROVIDERS` has an unknown token, or the discovery timeout is not a positive number | Use only `direct` and `proxy`, and fix the timeout |
176
+ | No `nous-proxy/` models appear | The proxy is down, not logged in, or `KXM_NOUS_PROXY_URL` is not loopback | Run `hermes proxy status`, log in, and use a loopback URL |
177
+ | A pinned model is still missing | The pin's hash, units or date failed, or one entry is invalid, such as an unverified zero rate | Fix the entry, recompute the hash, and refresh the pin within 30 days |
178
+ | KXM refuses a `nous-portal` route that Pi lists | `pi auth check` does not report `ready` | See the `provider_not_found` note above |
179
+ | A route is refused as not admitted | The selector is not in `.kxm/routes.yaml` or the role roster | Admission is a reviewed decision; see [Harness routing](../reference/harness-routing.md) |
180
+
181
+ ## Next steps
182
+
183
+ - Pick a route for a model reachable more than one way: [Harness routing](../reference/harness-routing.md)
184
+ - Run Pi agents under supervision: [Supervised Pi workers](pi-workers.md)
185
+ - Refresh the model inventory: [`kxm models`](../reference/cli-reference.md#kxm-models)
186
+ - All configuration layers and variables: [Configuration](../reference/configuration.md)