@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
@@ -1,437 +0,0 @@
1
- # Configuration reference
2
-
3
- KXM uses environment variables for the hub and Pi extension. The Claude Code plugin maps its settings to the same client values.
4
-
5
- ## Personalization and workflow settings (`kxm.config.v1`)
6
-
7
- `kxm config list|get|set` reads one merged view of three layers, in this order:
8
-
9
- 1. built-in defaults in `plugins/kxm/src/config.ts`;
10
- 2. user scope at `~/.config/kxm/config.yaml` (override the directory with
11
- `KXM_USER_CONFIG_DIR`);
12
- 3. project scope at `<repo>/.kxm/config.yaml`.
13
-
14
- `kxm config set <key> <value> --scope user|project` writes exactly one of those
15
- files, defaulting to project scope. `kxm config list --json` reports which file
16
- supplied what under `loadedFrom`; an empty `loadedFrom` means nothing is stored
17
- yet and every value shown is a built-in default. A stored value is not trusted
18
- because it is in the file: an unknown `hub.autoStart` fails closed to the
19
- default, and an unset `defaults.harness` means Pi rather than the first harness
20
- in the catalog.
21
-
22
- ### Improvement settings (`improvement.*`)
23
-
24
- `kxm improve` reads these keys from the project it runs in (and the user scope) and
25
- reports them in its output. They are normalized field by field whenever the
26
- configuration loads, so a typo falls back to the default instead of changing what the
27
- report says:
28
-
29
- | Key | Default | Accepted values; anything else becomes the default |
30
- |---|---:|---|
31
- | `improvement.promotionPolicy` | `manual_pr` | `manual_pr`, `critic_quorum`, or `auto_threshold` |
32
- | `improvement.telemetryHalfLifeDays` | `14` | A number greater than 0 and at most 3650 |
33
- | `improvement.autoThreshold.minRuns` | `10` | An integer from 1 to 1,000,000 |
34
- | `improvement.autoThreshold.minPassRate` | `0.95` | A number from 0 to 1 |
35
- | `improvement.autoThreshold.minCostSavings` | `0.5` | A number of at least 0 |
36
-
37
- None of these values can authorize or activate anything. The policy only selects which
38
- review-readiness rule `kxm improve` reports for each candidate, and every policy ends at
39
- an operator PR. The half-life weights report rows (`weightedRecurrence`) and never
40
- decides whether a group is a candidate. See
41
- [Continuous improvement](continuous-improvement.md#coded-repeats-kxm-improve).
42
-
43
- Project identity and repository bindings are separate, Git-tracked files under
44
- `.kxm/` (`project.yaml`, `roster.yaml`, `routes.yaml`, `gates.yaml`, `prices.yaml`,
45
- `roles/`, `workflows/`). They are configuration reviewed in a PR, not personal
46
- settings, and no panel or editor grants writer admission by editing them. See
47
- [Terminal components](tui-components.md) for the surface that renders them.
48
-
49
- ## KXM local project settings
50
-
51
- Root `kxm init` discovers the control Git worktree and does not use legacy
52
- `KXM_*` workspace overrides. A cloned multi-repository project can bind a
53
- member repository with a repeatable host-local argument:
54
-
55
- ```text
56
- kxm init --repository api=/absolute/path/to/api
57
- ```
58
-
59
- KXM validates the entire project and exact member Git identity before writing a
60
- bounded `kxm.local-repository-bindings.v1` record outside the project. The
61
- default record location is:
62
-
63
- - Windows: `%LOCALAPPDATA%\KXM\projects\<control-root-hash>\repository-bindings.json`;
64
- - macOS: `~/Library/Application Support/KXM/projects/<control-root-hash>/repository-bindings.json`;
65
- - Linux: `$XDG_STATE_HOME/kxm/projects/<control-root-hash>/repository-bindings.json`, falling back to `~/.local/state/kxm`.
66
-
67
- `KXM_STATE_HOME` may override the KXM state root with an absolute path for
68
- managed installations and tests. Relative overrides fail closed. A persistent
69
- SQLite file under the authoritative worktree's private Git metadata supplies a
70
- process-death-released writer mutex for create, repair, resume, and binding
71
- updates; choosing another `KXM_STATE_HOME` cannot bypass it. Absolute repository
72
- paths never enter Git configuration, and `--dry-run` validates and
73
- reports whether bindings would change without creating or updating local state.
74
-
75
- Newly created projects include `.kxm/template-provenance.yaml`. It records
76
- bounded exact-byte hashes and conservative authority-projection hashes for the
77
- built-in files, but does not make user files disposable. When the built-in
78
- template changes, `kxm init` performs whole-file three-way classification:
79
- `unchanged`, `user-only`, `template-only`, `converged`, or `conflict`. It applies
80
- only conflict-free template-only description/purpose changes after validating a
81
- complete shadow project. Any authority change, overlapping edit, template
82
- deletion, invalid shadow, or missing provenance remains planning-only.
83
-
84
- A live create or repair uses the fixed `.kxm-init-transaction` sibling at the
85
- Git root. Its exact operation record pins target hashes; repair preimages are
86
- backed up there, each destination is checked immediately before atomic
87
- replacement, and template provenance is installed last. The complete record is
88
- re-derived from supported built-in source and target templates before every
89
- resume. The transaction never grants repository bindings: an explicit binding
90
- is fully validated and persisted in Runtime-local state before project repair
91
- begins. If the process stops,
92
- the next `kxm init` verifies and resumes that exact operation. Do not commit the
93
- transaction directory. A dry-run may inspect it but never resumes, cleans, or
94
- rewrites it.
95
-
96
- ## Hub settings
97
-
98
- | Variable | Default | Description |
99
- |---|---:|---|
100
- | `KXM_HOST` | `127.0.0.1` | Listening interface |
101
- | `KXM_PORT` | `7331` | TCP port; `0` selects an available port |
102
- | `KXM_AUTH_TOKEN` | None | Administrative bearer token and fallback project token |
103
- | `KXM_PROJECT_TOKENS` | None | JSON object mapping project names to bearer tokens |
104
- | `KXM_WORKSPACE_DIR` | `.kxm` | Root for repository-local configuration, logs, assets, and state |
105
- | `KXM_CONFIG_DIR` | `.kxm/config` | Reviewable workspace configuration directory |
106
- | `KXM_LOGS_DIR` | `.kxm/logs` | Runtime log directory |
107
- | `KXM_ASSETS_DIR` | `.kxm/assets` | Durable workspace workflow assets |
108
- | `KXM_STATE_DIR` | `.kxm/state` | Restart-recovery state directory |
109
- | `KXM_DATA_PATH` | `.kxm/state/kxm.db` | SQLite database path; use `:memory:` only for disposable runs |
110
- | `KXM_SESSION_BRIEF` | picker on Pi TUI `startup`/`new`/`fork` | `off` disables the session-start task/plan picker only; status chrome still paints |
111
- | `KXM_LOG_PATH` | `.kxm/logs/kxm-hub.jsonl` | Structured hub JSON Lines log |
112
- | `KXM_MESSAGE_TTL_MS` | `86400000` | Default message lifetime, from 1 second through 7 days |
113
- | `KXM_MESSAGE_RETENTION_MS` | `604800000` | Time to keep terminal messages; minimum 1 second |
114
- | `KXM_RATE_LIMIT_MAX` | `600` | Requests accepted per client bucket and window |
115
- | `KXM_RATE_LIMIT_WINDOW_MS` | `60000` | Rate-limit window; minimum 100 milliseconds |
116
- | `KXM_WEBHOOK_WORKFLOWS` | None | Inline JSON array of signed webhook workflow definitions |
117
- | `KXM_WEBHOOK_WORKFLOWS_FILE` | None | Path to the workflow-definition JSON file |
118
-
119
- The hub's structured log (`KXM_LOG_PATH`) records the size of a context request, not its text: `context_packet_assembled` carries `taskChars`, `taskTokens` (distinct words after stopword removal) and `matchedCandidates` beside the selected ids, provenance summary and token estimate, and `context_recall` carries `queryChars`, `queryTokens`, `limit` and `results`. The task and query text appear only in the caller's own response.
120
-
121
- The hub refuses a non-loopback bind without `KXM_AUTH_TOKEN`. Use a long random administrative token even when project tokens are configured, because administrative endpoints such as `/metrics` require it outside loopback.
122
-
123
- When `KXM_AUTH_TOKEN` is unset, `kxm hub start` resolves credentials from the
124
- persisted `kxm.hub-env.v1` file under the user state root
125
- (`~/.local/state/kxm/hub-env.json`; honors `KXM_STATE_HOME` and platform
126
- equivalents). A missing admin token is generated once, persisted with `0600`
127
- permissions, and reused across hub restarts so workers and dashboards on the
128
- same machine share one stable credential. Explicit `KXM_AUTH_TOKEN` or
129
- `KXM_PROJECT_TOKENS` environment values take precedence and are persisted for
130
- later restarts. Delete the file and restart to rotate the generated token.
131
-
132
- Project tokens are an authorization boundary. A project-specific token can register only in its mapped project and see only that project's agents and messages. The administrative token remains a fallback for projects without an explicit entry. For provenance-gated workflows, configure an explicit project token and give workers only that token; reserve a distinct administrative token for operations such as quorum degradation approval.
133
-
134
- ### Hub auto-start (Pi extension)
135
-
136
- `hub.autoStart` in `kxm.config.v1` controls whether harness extensions start
137
- the hub themselves; the default is `background`. On every extension load, the
138
- Pi TUI first reuses a healthy bound hub (`kxm hub bind`), then a live local
139
- `hub.pid` claim, then a hub already answering on the configured
140
- `KXM_SERVER_URL` (for example one launched directly by a harness), and only
141
- starts a detached `kxm-hub.mjs` wrapper when none of them exists, logging
142
- wrapper output to `.kxm/logs/hub-autostart.log`. Set
143
- `hub.autoStart: off` to never start a hub from an extension. Auto-start
144
- resolves credentials before launch, so a first run generates the admin token
145
- and persists it under the user state root exactly as `kxm hub start` does;
146
- the extension then authenticates with the environment token, the auto-start
147
- token, or the persisted credential, in that order. A failed start notifies in
148
- the TUI and never blocks the session.
149
-
150
- PowerShell example:
151
-
152
- ```powershell
153
- $env:KXM_AUTH_TOKEN = "replace-with-an-admin-token"
154
- $env:KXM_PROJECT_TOKENS = '{"web":"web-token","api":"api-token"}'
155
- $env:KXM_WORKSPACE_DIR = "D:\work\product\.kxm"
156
- kxm hub start
157
- ```
158
-
159
- The four derived directories stay together when only `KXM_WORKSPACE_DIR` is set. Specific directory and file overrides exist for operator-managed volumes, but a normal repository should keep its configuration, logs, assets, and state under `.kxm`. Runtime logs and state are ignored by Git; configuration and intentional reusable assets may be reviewed and committed. Secrets remain in environment variables or a secret manager.
160
-
161
- ## Agent settings
162
-
163
- | Variable | Default | Description |
164
- |---|---|---|
165
- | `KXM_SERVER_URL` | `http://127.0.0.1:7331` | Hub base URL |
166
- | `KXM_AUTH_TOKEN` | None | Project token, or the shared administrative token |
167
- | `KXM_PROJECT` | package.json `name`, else current directory name | Discovery and message namespace |
168
- | `KXM_AGENT_NAME` | Harness-derived name | Unique live identity within a project |
169
- | `KXM_AGENT_PURPOSE` | Harness default | Capability description shown to peers |
170
-
171
- Names are case-insensitively unique among online agents in one project. A clean shutdown marks an identity offline. Reconnecting with the same project and name resumes its durable ID and rotates its agent key.
172
-
173
- ## Claude Code plugin settings
174
-
175
- | Plugin field | Environment value |
176
- |---|---|
177
- | KXM server URL | `KXM_SERVER_URL` |
178
- | Authentication token | `KXM_AUTH_TOKEN` |
179
- | Agent name | `KXM_AGENT_NAME` |
180
- | Agent purpose | `KXM_AGENT_PURPOSE` |
181
- | Project | `KXM_PROJECT` |
182
-
183
- `KXM_PROJECT_DIR` is supplied internally to derive a default project. Users normally should not set it.
184
-
185
- ## Environment-variable classification
186
-
187
- Names that look like `KXM_*` are not all operator configuration. This table is
188
- read from source; it does not invent defaults.
189
-
190
- | Name | Kind | Notes |
191
- |---|---|---|
192
- | `KXM_SLASH_SUBCOMMANDS` | TypeScript constant | Not an environment variable. Slash picker verbs in `session-work.ts`. Do not document as configuration. |
193
- | `KXM_UPDATE_CACHE` | TypeScript constant | Not an environment variable. Cache filename in `kxm-update.ts`. |
194
- | `KXM_UPDATE_SCHEMA` | TypeScript constant | Not an environment variable. Schema id `kxm.update.v1` in `kxm-update.ts`. |
195
- | `KXM_ASSET` | Internal release helper | GitHub release publish contract (`scripts/kxm-release-github.mjs`). Not operator configuration. |
196
- | `KXM_ASSET_PATH` | Internal release helper | Local tarball path for the same publish contract. Not operator configuration. |
197
- | `KXM_ASSET_SHA256` | Internal release helper | Declared digest checked against the local asset. Not operator configuration. |
198
- | `KXM_SMOKE_WEBHOOK_SECRET` | Internal gate-runner contract | Smoke workflow HMAC secret (`scripts/smoke-multi-pi.mjs`). Not operator configuration. |
199
- | `KXM_WORKER_IDENTITY_KEY` | Internal supervisor→child | Set by `scripts/kxm-worker.mjs` for the Pi extension. Not operator configuration. |
200
- | `KXM_WORKER_GENERATION` | Internal supervisor→child | Supervisor generation stamp for the child. Not operator configuration. |
201
- | `KXM_WORKER_CHILD_INCARCATION` | Internal supervisor→child | Child incarnation counter. Not operator configuration. |
202
- | `KXM_WORKER_STOP_AFTER_MS` | Internal supervisor→child | Optional supervisor self-stop used by tests. Not operator configuration. |
203
-
204
- ## Protocol limits
205
-
206
- | Behavior | Value |
207
- |---|---:|
208
- | Maximum message content | 32,000 characters |
209
- | Maximum HTTP request body | 256 KiB |
210
- | Default hop limit | 5 |
211
- | Maximum accepted hop limit | 20 |
212
- | Agent heartbeat interval | 10 seconds |
213
- | Agent stale threshold | 30 seconds |
214
- | Client request timeout | 15 seconds |
215
- | Default message TTL | 24 hours |
216
- | `kxm_await` wait | 60 seconds (default and maximum) |
217
- | Default `kxm_fanout` local wait | 30 minutes |
218
- | Default workflow signal wait | 24 hours |
219
- | Workflow signal wait range | 1 second to 30 days |
220
-
221
- The `ttlMs` field controls how long a request remains valid from the moment it is sent, including time queued behind other work. It is independent of `kxm_fanout.timeoutMs`, which only bounds how long the caller waits locally. Normally omit `ttlMs` for model work and keep the 24-hour default. A local wait timeout returns `status: pending`, the durable `messageId`, current message status, expiry, and `waitStatus`; it does not cancel or fail the request.
222
-
223
- Automated senders should set a stable `idempotencyKey` so an exact retry returns the original message instead of creating a duplicate. Reusing the key with different content returns a conflict. Do not create a new key while the original request is pending: use `kxm_get`, or repeat the exact fanout with the same correlation ID and idempotency prefix.
224
-
225
- `kxm_fanout` derives a bounded idempotency key from `idempotencyKeyPrefix`, the correlation ID when supplied, and the normalized target name. Reuse the same prefix and correlation ID for an exact retry of one workflow run. A later workflow may safely reuse the human-readable prefix with a different correlation ID without colliding with retained peer messages. Pending panel members have not supplied evidence and cannot satisfy a multi-agent workflow checkpoint.
226
-
227
- For a peer-policy requirement, transport correlation and idempotency do not
228
- establish provenance. Supply `workflowContext` with the exact run, stage,
229
- requirement, and active 1-based attempt. The hub authorizes and stores that
230
- context, and a checkpoint or wait cites the replied message IDs through
231
- `evidenceRefs`. Each reference set accepts 1–16 message IDs; quorum counts unique
232
- eligible stable producer IDs.
233
-
234
- When a Pi peer produces more than 32,000 characters, the extension returns a bounded truncated reply instead of leaving the request pending. The full output may remain in the replying agent's local Pi session or `.kxm/logs/pi-agent-<project>-<agent>-<identity>.log` when the long-lived worker is used.
235
-
236
- ## Long-lived worker settings
237
-
238
- | Variable | Default | Description |
239
- |---|---|---|
240
- | `KXM_WORKDIR` | Current directory | Repository used by the headless Pi worker |
241
- | `KXM_WORKER_LOG_PATH` | `.kxm/logs/kxm-worker-<project>-<agent>-<identity>.jsonl` | Structured worker lifecycle log |
242
- | `KXM_AGENT_LOG_PATH` | `.kxm/logs/pi-agent-<project>-<agent>-<identity>.log` | Captured headless Pi stdout and stderr |
243
- | `KXM_PI_COMMAND` | `pi` or `pi.cmd` | Explicit Pi executable path when it is not on `PATH` |
244
- | `KXM_WORKER_CONTINUE` | `true` | Resume the active binding's most recent Pi session after a restart |
245
- | `KXM_WORKER_INITIAL_CONTINUE` | same as `KXM_WORKER_CONTINUE` | Set `false` to start this supervisor generation fresh but still resume later recoveries |
246
- | `KXM_WORKER_SESSION_ISOLATION` | `off` for upgrade compatibility | `workflow` keeps ordinary work in one stable default Pi session and gives each durable workflow run a separate Pi session directory; `off` preserves the pre-isolation shared session |
247
- | `KXM_WORKER_MAX_RUN_SESSIONS` | `128` | Maximum retained workflow-specific Pi sessions per exact project/agent worker; integer `1`–`1024`, with least-recently-used inactive runs evicted |
248
- | `KXM_WORKER_DRAIN_MS` | `15000` | Graceful SIGTERM wait before SIGKILL |
249
- | `KXM_WORKER_MODEL` | Pi default | Optional model selector passed to Pi |
250
- | `KXM_WORKER_FALLBACK_MODELS` | unset | Up to eight comma-separated model selectors, tried in order after a final provider failure; requires a primary model |
251
- | `KXM_WORKER_PROVIDER_RETRY_MS` | `60000` | Retry delay (`1000`–`3600000`) after a final provider failure when no unused fallback remains |
252
- | `KXM_WORKER_TOOL_TIMEOUT_MS` | `1860000` | Maximum runtime for one Pi tool call (`1000`–`86400000`); the default leaves a one-minute supervisor grace above the longest 30-minute hub wait, and `0` disables the watchdog |
253
- | `KXM_WORKER_ACTIVATION_TIMEOUT_MS` | `60000` | Supervised-worker deadline (`1000`–`600000`) for a delivered custom message to start its model turn; expiry requests a restart while preserving the hub claim |
254
- | `KXM_WORKER_TOOLS` | Pi defaults | Optional comma-separated allowlist passed to Pi; use it to enforce read-only or single-writer roles |
255
- | `KXM_WORKER_EXTENSION_PATHS` | unset | Optional extension files separated by the platform path delimiter (`;` on Windows, `:` elsewhere); relative paths resolve inside `KXM_WORKDIR` |
256
- | `KXM_WORKER_SKILL_PATHS` | unset | Optional skill files or directories using the same delimiter and relative-path base |
257
- | `KXM_WORKER_MAX_RESTARTS` | Unlimited | Non-negative process restart limit; service managers may set their own policy |
258
- | `KXM_SMOKE` | unset | Set to `1` to enable the opt-in real multi-Pi smoke command |
259
- | `KXM_SMOKE_MODELS` | unset | Two distinct comma-separated model IDs for the real-Pi release smoke |
260
- | `KXM_SMOKE_TIMEOUT_MS` | `120000` | Per-phase real-Pi smoke timeout (`30000`–`600000`) |
261
- | `KXM_SMOKE_PI_COMMAND` | discovered `pi` | Optional explicit Pi executable for a self-hosted runner |
262
-
263
- `KXM_AGENT_NAME` and `KXM_PROJECT` are required by `kxm agent worker`. Session isolation is opt-in for upgrade compatibility: pass `--session-isolation workflow` or set the environment variable to `workflow` after reviewing the fresh scoped-session behavior. Both the CLI and direct `scripts/kxm-worker.mjs` default to `off`, so existing shared `--continue` histories are not silently abandoned. The remaining agent settings are inherited by the spawned Pi RPC process. The worker resolves `.kxm` and explicit package paths inside `KXM_WORKDIR`, creates the standard directories, and passes absolute paths to Pi. When either resource-path variable is set, the worker disables discovery for that resource category and loads only the listed files or directories; setting just one category leaves discovery unchanged for the other. Missing paths and extension directories fail before the restart loop. A skill may be a `SKILL.md` file or a directory Pi scans for skills. Restart the worker after changing any resource or path.
264
-
265
- Use exact paths for release verification or an uninstalled worktree. The antigravity provider is bundled inside `plugins/kxm` (vendored from pi-antigravity, MIT) — do NOT also load a standalone pi-antigravity extension; the bundled registration warns fail-loud on the duplicate. Include every other provider extension the selected models require because extension discovery is isolated:
266
-
267
- ```powershell
268
- $separator = [IO.Path]::PathSeparator
269
- $env:KXM_WORKER_EXTENSION_PATHS = @(
270
- "plugins/kxm/src/extension.ts"
271
- ) -join $separator
272
- $env:KXM_WORKER_SKILL_PATHS = "plugins/kxm/skills/kxm"
273
- $coordinatorTools = @(
274
- "read", "powershell", "edit", "write", "grep", "find", "ls",
275
- "kxm_list", "kxm_send", "kxm_fanout", "kxm_get", "kxm_await",
276
- "kxm_workflow_get", "kxm_workflow_checkpoint", "kxm_workflow_wait",
277
- "kxm_workflow_record", "kxm_improvement_report"
278
- ) -join ","
279
- kxm agent worker --name coordinator --project product `
280
- --model antigravity/gemini-3.8-flash-high `
281
- --fallback-models openrouter/qwen/qwen3-coder-plus --tools $coordinatorTools `
282
- --session-isolation workflow --fresh-start
283
- ```
284
-
285
- The worker is Pi-only, so the primary model and every fallback pass the same native-vendor brake as assignment before Pi starts: a model whose vendor has its own harness (Anthropic, OpenAI, xAI, Moonshot, Google, DeepSeek) is refused with `pi_native_impersonation_blocked` whether it is named directly (`xai/…`), through that vendor's own Pi provider (`openai-codex/…`, `kimi-coding/…`, `claude-bridge/…`), or behind an aggregator (`openrouter/x-ai/…`). The one Google exception is the decided `antigravity/gemini-*` route. Which routes are *admitted* is still Tracking's call; the brake only refuses.
286
-
287
- With workflow isolation enabled, the hub stamps every internal workflow prompt, callback resume, timeout notification, and authorized peer-evidence request with a canonical `workflowRunId`. Before acknowledging a queued message, the Pi extension compares that hub-owned binding with the active worker scope. A mismatch is left `queued`; the extension atomically requests a route change and shuts down cleanly. Only after the child closes does the supervisor start one replacement Pi RPC child with `--session-dir .kxm/state/pi-sessions/<workerKey>/default` or `.../runs/<runId>`. This gives the stable default work and each `{agent, workflowRunId}` an independent Pi JSONL history without concurrent writers. Correlation IDs alone never select a workflow session. Binding manifests and requests are identity-, supervisor-generation-, child-incarnation-, timestamp-, and schema-checked, and malformed manifests are quarantined before a safe default binding is created.
288
-
289
- Explicit extension code runs with the worker's repository, network, and model credentials, and skills supply privileged instructions. These are trusted service-administrator settings: never derive them from a webhook or workflow payload. Absolute and parent-relative paths outside `KXM_WORKDIR` are intentionally supported for reviewed provider extensions. Review and protect every configured resource like an executable dependency. A fast `--continue` failure writes a collision-safe `.kxm/state/worker-recovery-<project>-<agent>-<identity>.json` envelope and retries once without `--continue`; the reader can consume an exact-name legacy envelope during migration.
290
-
291
- Pi performs its own transient retries before emitting the final settled event. If the final assistant outcome is still a provider error, the extension leaves the durable inbound message delivered instead of replying with an error. The supervisor closes the RPC session gracefully, records only an allowlisted diagnostic class in its structured log, selects the next configured fallback, and resumes the current Pi session so completed tool and peer results remain available. If continuation is structurally invalid, the existing fresh-session recovery path takes over. Raw provider output remains only in the protected `pi-agent-*.log` stream; even oversized or malformed RPC frames are reduced to bounded metadata in supervisor memory and lifecycle logs.
292
-
293
- The tool allowlist is a capability boundary inside Pi, not a prompt suggestion — but it bounds **tool names, not filesystem paths**. A worker that keeps `write`, `edit`, or a shell tool can modify any file its OS user can reach; there is no path jail, and workspace roster fields such as `ownership` or `roles` are not read by the launcher. A review-only worker can use `read,grep,find,ls`; a coordinator should add only the hub tools required by its workflow. The example above is a full-lifecycle, single-writer PowerShell coordinator; replace `powershell` with `bash` on macOS or Linux. Omit both platform shell tools, `edit`, and `write` from peers that must not mutate a shared checkout. Durable coordinators need `kxm_workflow_checkpoint`, and workflows that pause for external gates or capture learning also need `kxm_workflow_wait`, `kxm_workflow_record`, and `kxm_improvement_report`. If an enabled tool exceeds the watchdog duration, the worker preserves recovery metadata, closes or force-stops the RPC process tree within the drain deadline, and resumes the delivered request. Choose a timeout above the longest expected build or browser test and keep an external service-manager limit as a second boundary.
294
-
295
- ## Operator CLI
296
-
297
- The current hub command groups are `agent`, `session`, `workflow`, `gate`, `hub`, `dash`, `improve`, `context`, and `skills`; the root `init` command is the first configuration-only KXM slice. The CLI is an operator **client**: the hub's durable state, the protocol and schema types, and reviewed Git configuration define behaviour; where the CLI diverges from them, the CLI is the defect.
298
-
299
- | Command | Purpose |
300
- |---|---|
301
- | `kxm init` | Atomically create a provenance-tracked minimal KXM project, validate it without rewriting, resume a pinned interrupted create/repair, apply conflict-free non-authority template updates, or join an existing clone with repeatable `--repository <id=absolute-path>` member bindings stored outside Git. `--dry-run` performs no writes. Provenance-free/ambiguous repair and permission-expanding changes remain planning-only. These configuration slices do **not** activate a KXM Runtime. `kxm init` is project-only; bind a running hub with `kxm hub bind <url>` |
302
- | `kxm tenant status` | One composed read for machine clients (the portal backend): hub metadata (agent roster, message queue, plans, the hub own workflow runs with stages/progress) and the Runtime **authoritative** run state (event-log folded, per-run `homeRuntimeId`), every value labelled with its source. Reads both sources concurrently with a hub deadline (5 s default); an unreadable upstream becomes `unavailable` with a stable reason (`hub_unreachable`, `hub_timeout`, `hub_unauthorized`, `hub_response_invalid`, `hub_credential_unreadable`, `runtime_supervisor_not_running`) instead of being filled from the other source. The cross-check is honest about id spaces: hub and Runtime runs mint ids independently, so no shared id reports `unverified` (`run_identity_link_absent`) — never agreement; shared ids are compared and disagreements listed; a Runtime row whose event-log fold failed is labelled `runtime-cached` and excluded from the comparison (`unverifiedFoldRuns`), never counted as agreement. `degraded` marks a partial read. Attaches to a live supervisor and never starts one; resolves the **admin** credential only (a project token cannot read the snapshot). Requires a KXM project |
303
- | `kxm trust diff [--base <rev>]` | Print the structured `kxm.permission-diff.v1` report between a base Git revision (default `HEAD`, materialized into a temporary shadow with a sanitized environment) and the working tree: every authority-bearing field change classified as expansion, narrowing, or neutral with per-field hashes. Performs no project writes |
304
- | `kxm trust check [--base <rev>]` | Exit non-zero when any expansion exists, so an authority-bearing change cannot merge without a reviewed Git change. Formatting/description-only changes never require review |
305
- | `kxm run <workflow> [prompt]` | Auto-start the KXM Runtime supervisor if needed, then create an immutable run offline: pins `homeRuntimeId` plus config/executor/tool policy revisions and stores only the prompt hash. `--dry-run` prints the plan without creating anything |
306
- | `kxm runs status <runId>` | Show the projected status of a run from its event sequence |
307
- | `kxm runs cancel <runId>` | Durably request cancellation (ordered `run.cancel_requested` then `run.status_changed` events; idempotent, terminal runs are no-ops). `--dry-run` writes nothing |
308
- | `kxm runs list` | List recent runs for the current project |
309
- | `kxm runtime start \| status \| stop` | Manage the detached KXM Runtime supervisor: auto-start with liveness probe, token-authenticated 127.0.0.1 API, crash recovery with a stable logical runtime identity |
310
- | `kxm agent worker` | Start a long-lived Pi worker. Use `--session-isolation workflow` to enable per-workflow Pi contexts; the upgrade-compatible default is `off`. Does not read a workspace `agents.json`; pass `--model`, `--tools`, and related flags explicitly |
311
- | `kxm session start --id <id> (--mix a,b \| --workflow <definitionId>)` | Write a `kxm.session.v1` manifest under `.kxm/assets/sessions/<id>/` and create asset directories. **Does not start any process.** `--workflow` records the whole roster, not the definition's participants |
312
- | `kxm session brief [--status]` | Read-only local hub snapshot of recent tasks (workflow runs) and plans (journal). `--status` prints the status line for harness chrome. No message bodies. Does not start a hub |
313
- | `kxm session status` | Show PID claim files and recovery envelopes under `.kxm/state`; does not read `session.json` |
314
- | `kxm session stop` | Request shutdown of **every** managed hub and worker process in the workspace — the same operation as `kxm hub stop`; not scoped to a session |
315
- | `kxm workflow list \| get \| start \| export` | Inspect, start, or export workflow runs. `list`/`get`/`export` read the **local** `.kxm/state/kxm.db`, not the configured hub |
316
- | `kxm gate validate` | Parse the same active source the hub loads without printing secrets. Explicit `--file` wins; otherwise configure exactly one of `KXM_WEBHOOK_WORKFLOWS_FILE` or inline `KXM_WEBHOOK_WORKFLOWS`. Missing or ambiguous sources exit 2 |
317
- | `kxm gate artifacts-exist --path <asset>` | Verify one non-empty regular file resolves within the configured workspace assets root; lexical or real-path escape fails closed |
318
- | `kxm gate degrade <runId> <stageId> --requirement <key> --reason <text>` | Use the administrative token to approve a policy-declared lower peer minimum for the current attempt |
319
- | `kxm gate signal` | Post a signed workflow callback |
320
- | `kxm gate github watch` | Poll required GitHub checks and post the existing signed signal |
321
- | `kxm init` | Create or validate a project; configuration remains project-owned and no package dogfood templates are copied |
322
- | `kxm hub view` | Check `/health` and `/ready` |
323
- | `kxm hub bind <url>` | Bind this machine to a running hub. A **remote** URL is refused unless a credential resolves (`KXM_AUTH_TOKEN`, or the persisted hub record); `kxm hub view` reports the binding as `loopback` or `remote` |
324
- | `kxm hub unbind` | Remove this machine's hub binding |
325
- | `kxm update --check` / `kxm update --kxm` | Check or apply a kxm operator package update from an npm-global install only. Other install kinds (source checkout, Pi git, Claude marketplace, npm-local, unknown) refuse `--kxm` and skip auto-apply. Source checkouts neither fetch nor nag. Default source is GitHub release tarballs; the release asset `kxm-<v>.tgz` must carry a sha256 digest or install fails closed. `source: npm` is for after the public package exists. Optional per-user `update.yaml` (`kxm.update.v1`, `auto` boolean) under the host state root (`KXM_STATE_HOME` / `%LOCALAPPDATA%\KXM` / macOS Application Support / XDG state) enables auto-apply on `kxm update`. A project `.kxm/update.yaml` is ignored with a warning. Notice also prints on `kxm hub start` (not from source) and on the session widget from cache |
326
- | `kxm dash` | Open the read-only SSE observer dashboard; non-TTY output is one ANSI-free snapshot |
327
- | `kxm hub start` | Start the KXM hub in the foreground |
328
- | `kxm hub stop` | Request managed hub and worker shutdown |
329
- | `kxm improve` | Propose coded-repeat candidates from routing records: the current project's Runtime event store (read-only) and `.kxm/logs/telemetry.jsonl`, or only the file named by `--file`. Prints the sources it read, writes proposed candidates under `.kxm/candidates/`, and reports promotion readiness under `improvement.promotionPolicy`; nothing is applied and no policy authorizes. Does not read the workflow journal |
330
- | `kxm context get \| recall \| state \| episode \| promote \| explain \| wiki-compile \| wiki-lint` | Context operating system: role-aware packets, metadata search, temporal state, episodes, evidence-backed lineage (`explain`), wiki compile/lint |
331
- | `kxm skills` | Governed skill candidate lifecycle |
332
- | `kxm memory sync` | Regenerate the read-only project-memory block — authored facts from `.kxm/memory/` only — between `<!-- kxm:memory:start -->` and `<!-- kxm:memory:end -->` in whichever of `AGENTS.md`, `CLAUDE.md` and `GEMINI.md` already exist in the current directory. Text outside the markers is never rewritten; a file without markers gets the block appended. Each file must hold exactly one start marker followed by exactly one end marker, or neither: an orphan marker, an end before its start, or a second block makes sync exit 1 naming the file and the problem, and **no file is written**, the well-formed ones included. Missing files are reported as `missing` and **not created** — which harness a project uses is its own choice — and with none present sync exits 1 without writing. `--json` reports `updated`, `unchanged` and `missing` |
333
-
334
- Telemetry events carry a `target` label: `project` whenever a project or workflow identity is present, and `cli` for unscoped operator behavior. `KXM_IMPROVE_TARGET=cli` or `KXM_IMPROVE_TARGET=project` overrides that label when an event is written. No report reads the label, and `kxm improve` has no `--target` option.
335
-
336
- Journal entries recorded with `kxm workflow record` or `kxm_workflow_record` take one of ten categories (`plan`, `decision`, `contradiction`, `error`, `lesson`, `observation`, `hypothesis`, `experiment`, `state-change`, `skill-candidate`). `--stage-id` binds the entry to a stage; the hub derives the attempt, and the area defaults to the stage's declared area. The journal covers hub webhook runs only; a `kxm run` id is refused with `workflow_not_found`.
337
-
338
- The gate group contains exactly the five implemented gates listed above. Names declared in a workspace `gates.json` that do not map to one of them (for example `quality`, `git-commit`, `jira-fetch`) are records with no runner; there is no `kxm gate run <name>`.
339
-
340
- Global flags: `--json`, `--dry-run`, `--workspace`. Project-root `kxm init` discovers from the current directory, rejects `--workspace`, and intentionally ignores legacy `KXM_*` workspace overrides; `--workspace` continues to scope current hub commands. Root init accepts repeated `--repository <id=absolute-path>` member bindings and uses the platform-local state root described above. `kxm workflow start <definitionId> --payload <JSON|@file>` creates a signed webhook delivery. With an active definition source, start, signal, and GitHub watch resolve that definition's `secretEnv` / `signalSecretEnv`; when no separate signal secret is declared, callbacks use the workflow-start secret, matching the hub. Generic credential variables are used only when no active definition source is configured. `--dry-run` never appends telemetry. Non-dry-run gate evidence and summaries are written to the protected telemetry JSONL after configured-value redaction; do not place unnecessary sensitive text in evidence. `kxm gate degrade` requires `KXM_AUTH_TOKEN` to contain the administrative token; use `--dry-run --json` first and never put a secret in its reason. `kxm agent worker --name <name> --project <project>` and `kxm hub start` honor the same workspace flag. `--no-continue` disables every session resume; `--fresh-start` skips only the initial resume. `--session-isolation workflow` enables isolated contexts and starts a fresh scoped default history on first use; `--session-isolation off` is the upgrade-compatible default and keeps the former shared Pi history. GitHub watch posts an exact signed `failed` signal on timeout and exits `4`, preserving the distinction from a successful gate.
341
-
342
- **`--dry-run` changes nothing.** Every command either only reads, or stops at its plan: the envelope it prints when it runs, with `dryRun: true` and a `planned` list of `{ "action", "target" }` entries (`write`, `delete`, `move`, `request`, `ssh`). A dry run writes no file, sends no mutating hub request, starts no Runtime supervisor, persists no session token, and runs nothing on a remote host; its reads of local SQLite stores do not even leave `-wal`/`-shm` sidecars behind. `kxm backup --dry-run` lists the stores and target files without opening a source store (opening one checkpoints its WAL); `kxm restore --dry-run` verifies the manifest and every backup digest, checks each store's recorded schema version against this build's ceiling, and lists the stores it would overwrite — a real restore now runs the same checks for every store before it overwrites the first. A create that assigns an id when it runs (`goal create`, `task create`, `memory note`) plans with a preview id the real run will not reuse. A command that cannot say what it would do without doing part of it refuses with exit `2` and `dry_run_unsupported` instead of running: `kxm runs status|list|receipt` when no supervisor is running (answering would start one) and the interactive `kxm models` screen. That refusal is also the default: the CLI keeps one list of the commands that answer `--dry-run`, and any command missing from it is refused before its action runs.
343
-
344
- ## Webhook workflow settings
345
-
346
- Configure either `KXM_WEBHOOK_WORKFLOWS` or `KXM_WEBHOOK_WORKFLOWS_FILE`, never both. A definition selects a provider source, project, coordinator, event and payload filters, prompt template, and ordered stages. Use `secretEnv` to resolve the workflow-start HMAC secret from another environment variable. Use the optional `signalSecretEnv` for a separate callback secret; otherwise external signals use the workflow-start secret. Do not store either secret in JSON.
347
-
348
- See [Webhook workflows](webhook-workflows.md) for the base schema and the complete Jira configuration under `.kxm/workflows`. See [Peer provenance and quorum gates](provenance-gates.md) for `evidencePolicies`, `workflowContext`, `evidenceRefs`, and explicit degradation.
349
-
350
- ## Delivery modes
351
-
352
- | Mode | Use it when | Effect |
353
- |---|---|---|
354
- | `followUp` | Normal delegation | Handle after current work settles |
355
- | `steer` | An active blocker requires a course change | Deliver at the next decision boundary |
356
- | `nextTurn` | Information should wait for a later turn | Queue context without immediate work |
357
-
358
- `followUp` is the safe default. Load values through your shell, supervisor, container platform, or secret manager using the variables documented on this page and in the [KXM Handbook](kxm-handbook.md). Never commit real tokens.
359
-
360
- ## Nous providers (opt-in)
361
-
362
- Unset `KXM_NOUS_PROVIDERS` leaves startup synchronous and offline: no fetch,
363
- no `registerProvider`, no notice. Models are never auto-selected. There is no
364
- preference overlay and no writer/router admission.
365
-
366
- ### Clean-machine setup order
367
-
368
- Direct API (no Hermes):
369
-
370
- 1. Obtain a Nous API key from the vendor.
371
- 2. `export NOUS_API_KEY=...` in the shell or supervisor that starts Pi.
372
- 3. `export KXM_NOUS_PROVIDERS=direct`
373
- 4. Optionally point `KXM_NOUS_CATALOG_FILE` at a dated `kxm.nous-catalog.v1`
374
- pin (see `test/fixtures/nous/catalog-empty.json` for the empty template).
375
- 5. Start Pi. Models appear as `nous/<id>` only when capacity and verified
376
- numeric rates are known from `/v1/models` or the pin.
377
-
378
- This slice reads **only** `NOUS_API_KEY` for direct auth. It does not discover
379
- models from stored Pi `/login` credentials.
380
-
381
- Hermes subscription proxy (direct API is not required):
382
-
383
- 1. Install Hermes yourself if it is missing. KXM does not install it.
384
- 2. Log in with the installed command: `hermes login --provider nous`.
385
- Newer docs also mention `hermes setup --portal`; that flow is not claimed
386
- working on every CLI.
387
- 3. Start the local proxy: `hermes proxy start`. Check `hermes proxy status`.
388
- Default base URL is `http://127.0.0.1:8645/v1`.
389
- 4. `export KXM_NOUS_PROVIDERS=proxy`
390
- 5. Start Pi. Models appear as `nous-proxy/<id>` with display suffix
391
- `subscription proxy, market ref`.
392
-
393
- KXM never runs login, install, proxy start, or paid requests for you.
394
-
395
- ### Environment
396
-
397
- - `KXM_NOUS_PROVIDERS`: comma list of `direct` and/or `proxy`. Unknown tokens
398
- fail closed: nothing is registered.
399
- - `KXM_NOUS_PROXY_URL`: optional loopback `http`/`https` URL
400
- (`127.0.0.1`, `localhost`, or `::1` only). Non-loopback fails closed.
401
- - `KXM_NOUS_DISCOVERY_TIMEOUT_MS`: bounded GET `/v1/models` timeout, default
402
- `5000`.
403
- - `KXM_NOUS_CATALOG_FILE`: operator pin with `schema`, `recordedAt`, `source`,
404
- `units` (`usd_per_million_tokens`), `hash` (`sha256:` of canonical
405
- recordedAt/source/units/models), and per-model capacity plus four finite
406
- nonnegative rates. Verified zeros are allowed; unverified zeros, stale
407
- pins (older than 30 days), missing units, or a bad hash exclude data.
408
- Per-context source tiers are folded into a labeled upper bound.
409
-
410
- Public GET `https://inference-api.nousresearch.com/v1/models` catalog fields
411
- are observed: `context_length`, `top_provider.max_completion_tokens`,
412
- `architecture.input_modalities`, `supported_parameters` (`tools` /
413
- `reasoning`), and `pricing.prompt` / `completion` / `input_cache_read` /
414
- `input_cache_write` as per-token decimal strings plus `pricing.overrides[]`
415
- (`min_prompt_tokens` and its own prices). Those rates convert once to
416
- `usd_per_million_tokens`. `pricing.original` and a blanket discount are never
417
- applied. Incomplete or malformed live rates exclude the model rather than
418
- dropping a costly tier or guessing zero, unless a matching dated pin supplies
419
- verified rates and capacity. Context tiers are represented as the highest
420
- per-component bound. That bound is what Pi `calculateCost` sees: source tiers
421
- stay discovery/build metadata and are not registered as a `cost.tiers`
422
- schedule that can underquote at an exact threshold. Upper-bound estimates are
423
- labeled in both `nous/*` and `nous-proxy/*` display names (proxy keeps
424
- `subscription proxy, market ref`). Source URL, fetch date, and raw SHA stay
425
- on the discovery report. **Compatibility (2026-09-07):** tests verified one
426
- streamed tool call plus usage on `qwen/qwen3-coder-plus` for the direct API
427
- and an OAuth-backed Hermes proxy. Both recorded usage. Included subscription
428
- quota consumed and extra billed amount remain unknown. Other models and
429
- automatic auth refresh remain unverified. Official Nous native Messages
430
- support is documented for `anthropic/*` only; Qwen uses chat/completions, so
431
- direct Claude→Nous→Qwen is unsupported by that route
432
- ([hermes_cli/providers.py](https://github.com/NousResearch/hermes-agent/blob/main/hermes_cli/providers.py),
433
- observed 2026-09-07). A mocked env bearer proves header support, not OAuth
434
- credential interchangeability. KXM does not start the Hermes proxy; an
435
- operator isolated test did. Default configuration is unchanged.
436
- Assumed OpenAI-style fixtures under `test/fixtures/nous/` still cover the
437
- older numeric `cost` shape.