@kontextmind/kxm 0.7.167 → 0.7.169
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +30 -0
- package/docs/contributing/ci-and-release.md +6 -1
- package/docs/operations/runtime-sync.md +2 -1
- package/docs/operations/troubleshooting.md +4 -0
- package/docs/operations/upgrade.md +18 -3
- package/docs/operations.md +70 -7
- package/docs/reference/cli-reference.md +21 -6
- package/docs/reference/config-reference.md +28 -13
- package/docs/start/install.md +1 -1
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/claude-hook.js +170 -36
- package/plugins/kxm/dist/cli.js +451 -132
- package/plugins/kxm/dist/extension.js +184 -53
- package/plugins/kxm/dist/mcp-server.js +97 -40
- package/plugins/kxm/dist/runtime-supervisor.js +240 -47
- package/plugins/kxm/dist/runtime.js +240 -47
- package/plugins/kxm/dist/server.js +9 -0
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/kxm-definitions/SKILL.md +3 -2
- package/plugins/kxm/skills/kxm-harness-auth/SKILL.md +4 -2
- package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +9 -4
- package/plugins/kxm/src/cli/hub.ts +42 -7
- package/plugins/kxm/src/cli/system.ts +3 -1
- package/plugins/kxm/src/cli/types.ts +5 -3
- package/plugins/kxm/src/cli.ts +2 -1
- package/plugins/kxm/src/engine.ts +105 -8
- package/plugins/kxm/src/hub-binding.ts +301 -55
- package/plugins/kxm/src/hub-identity.ts +17 -9
- package/plugins/kxm/src/kxm-update.ts +29 -6
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/project-config.ts +63 -1
- package/plugins/kxm/src/runtime-supervisor.ts +22 -4
- package/scripts/kxm-publish-npm.mjs +47 -1
package/CHANGELOG.md
CHANGED
|
@@ -181,6 +181,18 @@ All notable user-facing changes are documented here. The project follows [Semant
|
|
|
181
181
|
|
|
182
182
|
### Changed
|
|
183
183
|
|
|
184
|
+
- **Tool policy is enforced at load and before dispatch.**
|
|
185
|
+
`coordinator` and `read-only` select the read-only one-shot profile.
|
|
186
|
+
`workspace-writer` and `tests-writer` select the edit profile. Dispatch
|
|
187
|
+
uses the narrowest of the role `permission`, that preset profile, and the
|
|
188
|
+
step's repository access. An agent preset wider than its role is
|
|
189
|
+
`tool_preset_exceeds_role` at load, and `step_unsupported` before a
|
|
190
|
+
producer starts if those files were already loaded. A write step whose
|
|
191
|
+
resolved profile is read-only is the same handoff. The detail names the
|
|
192
|
+
role permission and the step access. `tools.allow` and `tools.deny` stay
|
|
193
|
+
on the MCP surface through `enforceToolPolicy`. See
|
|
194
|
+
[agent files](docs/reference/config-reference.md#kxmagentsidyaml-kxmagentv1).
|
|
195
|
+
|
|
184
196
|
- **The checked-in price catalog and model inventory match the live OpenRouter and Nous feeds.**
|
|
185
197
|
`.kxm/prices.yaml` is dated 2026-09-28. It adds `xai/grok-4.7` (alias
|
|
186
198
|
`x-ai/grok-4.7`) at $1.60 input and $4.80 output per 1M tokens, with cache
|
|
@@ -605,6 +617,24 @@ All notable user-facing changes are documented here. The project follows [Semant
|
|
|
605
617
|
|
|
606
618
|
### Fixed
|
|
607
619
|
|
|
620
|
+
- **`kxm hub view` and `kxm hub bind` require a kxm hub body.** HTTP 200 HTML
|
|
621
|
+
(an Authentik login page) and 30x redirects are not healthy. The JSON
|
|
622
|
+
`health` field is `{ "error": "auth_proxy" }`, not the page. Bind refuses
|
|
623
|
+
with `hub_not_kxm` unless `--force` is set. A timeout or a dead host still
|
|
624
|
+
binds. `kxm hub view` names the key source that would supply the token
|
|
625
|
+
(`env:<NAME>` only when that variable is set, `op:<ref>`, `token-command`,
|
|
626
|
+
`hub-env`, or `missing`).
|
|
627
|
+
- **A cloud bind no longer breaks a 0.7.159 Runtime supervisor.** Cloud fields
|
|
628
|
+
live in `hub-binding.cloud.json`. `hub-binding.json` stays a three-key local
|
|
629
|
+
record or is omitted, so the old reader falls back to the local hub instead
|
|
630
|
+
of throwing `malformed hub binding` and stopping sync. A newer schema is a
|
|
631
|
+
warning and `no_hub`, not a stalled tick. Restart the supervisor, hub, and
|
|
632
|
+
workers after upgrading and before `kxm hub bind --cloud`.
|
|
633
|
+
- **`kxm update --kxm` downloads with curl when `gh` is missing**, and still
|
|
634
|
+
verifies the release sha256.
|
|
635
|
+
- **The npm publish job waits until `npm view` shows the version** (bounded)
|
|
636
|
+
before it reports success. GitHub release log lines no longer say "published"
|
|
637
|
+
in a way that means the package is on npm.
|
|
608
638
|
- **A one-shot outcome is the last top-level JSON object that ends the reply.** It is accepted only when the prefix before it leaves every string, object, and array closed (a naive state machine plus a container lexer over the last container openers). Anything ambiguous, truncated, or followed by prose fails closed. The authoring witness counts `HEAD`, so a writer that commits is credited.
|
|
609
639
|
|
|
610
640
|
- **The test suite no longer passes `--test-timeout`.** Under `node --test` that flag bounds each file, so coverage on CI timed out `test/core/engine.test.ts` at three minutes. The wall clock in `scripts/run-bounded.mjs` still bounds each script.
|
|
@@ -201,7 +201,12 @@ versions by hand.
|
|
|
201
201
|
4. **Publish npm** runs in the protected `npm-publish` environment. It skips a
|
|
202
202
|
version already on npm. Otherwise `scripts/kxm-publish-npm.mjs` confirms the
|
|
203
203
|
GitHub release is published, downloads the asset, verifies its sha256
|
|
204
|
-
against the release digest, and runs `npm publish` on that exact file.
|
|
204
|
+
against the release digest, and runs `npm publish` on that exact file. The
|
|
205
|
+
job then polls `npm view @kontextmind/kxm@<version> version` (up to 20
|
|
206
|
+
minutes, `KXM_NPM_VISIBLE_WAIT_MS=0` skips the wait) and reports success
|
|
207
|
+
only after the registry shows that version. Log lines that say the GitHub
|
|
208
|
+
release is public are not an npm publish. The registry can lag the GitHub
|
|
209
|
+
release by many minutes.
|
|
205
210
|
|
|
206
211
|
Every step is idempotent. Rerunning the Release workflow for a tag that is
|
|
207
212
|
already published or already on npm reports it and changes nothing.
|
|
@@ -94,8 +94,9 @@ sync prj_a17d607765e144cd95b93a8715d360b6: blocked (pending 0, acked 1, refused
|
|
|
94
94
|
| State | Meaning | Action |
|
|
95
95
|
|---|---|---|
|
|
96
96
|
| `ok` | Rows are being acknowledged | None |
|
|
97
|
-
| `no_hub` | No hub is bound or set; rows are kept locally by design | Bind a hub if you want hub-side views |
|
|
97
|
+
| `no_hub` | No hub is bound or set, or this build ignored a binding it does not understand; rows are kept locally by design | Bind a hub if you want hub-side views. A warning that names `hub-binding.json` means restart the supervisor after upgrading, then bind again |
|
|
98
98
|
| `blocked` | Transport or credential failure; rows stay pending and the tick backs off, up to 5 minutes | Fix the cause; the next attempt resumes on its own |
|
|
99
|
+
| `sync: the supervisor is running but did not answer /v1/sync/status` | The process is up, and `kxm runtime status` could not read `GET /v1/sync/status`. A hung supervisor, a token mismatch, or a supervisor started before an upgrade | `kxm runtime stop`, then `kxm runtime start`. Restart the hub and workers too after an upgrade and before a cloud bind |
|
|
99
100
|
| `refusing` | The hub durably refused rows, or answered without a result for some | Fix the hub side, then run `kxm runtime sync-retry` |
|
|
100
101
|
|
|
101
102
|
A project whose run store this release cannot open shows `blocked (its store is not readable by this build)` with the reason; see [Upgrade KXM](upgrade.md#understand-schema-changes). Right after the supervisor starts, the status can read `no project registered with this Runtime yet` until the first tick.
|
|
@@ -89,6 +89,7 @@ If a malformed claim remains, read the exact `.pid` JSON in the state directory
|
|
|
89
89
|
| `hub_credential_unreadable` | Repair or remove `hub-env.json` under the user state root |
|
|
90
90
|
| `cloud_token_missing` | A `--cloud` binding's variable is empty and it has no working command. Export the variable or fix `--token-command`. This machine's hub-env token is not sent |
|
|
91
91
|
| `cloud_flag_required` | `--token-command` was passed without `--cloud`. `--token-env` and `--key-op` are key references and are valid on a local bind |
|
|
92
|
+
| `hub_not_kxm` | The URL returned an HTML login page or a 30x redirect, not a kxm `/health` body. `https://hub.kxmd.dev` is an Authentik forward-auth page. Bind the SSH forward `http://127.0.0.1:17331`. `--force` records the URL anyway and does not make the proxy a hub |
|
|
92
93
|
| 401 after binding a loopback forward | The bind was not `--cloud`, so the client sent the local hub-env token. See [Cross-box peer attach](../operations.md#cross-box-peer-attach) |
|
|
93
94
|
|
|
94
95
|
## Claude Code plugin and MCP
|
|
@@ -209,6 +210,9 @@ A gate step declares an outcome its `expect` value never produces. The message n
|
|
|
209
210
|
| `runtime supervisor is not running` or `runtime_not_running` | The supervisor stopped | `kxm runtime start`; commands such as `kxm run` also start it on demand |
|
|
210
211
|
| `runtime_supervisor_unreachable` | A live supervisor process does not answer its token probe | Check the PID from `kxm runtime status`, stop a hung process with your OS tools, then `kxm runtime start` |
|
|
211
212
|
| `project_required` | The command ran outside a KXM project | Run it from the checkout, or run `kxm init` |
|
|
213
|
+
| `project_home_conflict` | This checkout is not the registered home for that project id. A different repository already owns it, the home runtime is immutable, or the primary checkout is already the home row | Use the original checkout, or a worktree of that repository. Do not copy the project id into an unrelated clone, and do not delete the database |
|
|
214
|
+
| `runtime_schema_newer` | The store was written by a newer release than this build | Upgrade KXM. Do not delete the database |
|
|
215
|
+
| `sync: the supervisor is running but did not answer /v1/sync/status` | The supervisor process is up, and `GET /v1/sync/status` failed. A hung process, a token mismatch, or a supervisor started on an older release | `kxm runtime stop`, then `kxm runtime start`. After an upgrade, restart the hub and workers before a cloud bind. See [Check sync status](runtime-sync.md#check-sync-status) |
|
|
212
216
|
| `producer_route_not_admitted` | A live drive uses a model route that is not admitted | `kxm routes admit --model <provider/model>`, or drive with `--simulated` |
|
|
213
217
|
| A 429, timeout, or provider error fails the attempt on the first route | The role's `policy.fallback.onError` is empty, omits that class, or `maxSwitches` is already spent. Cancellation, policy refusal, and authentication do not walk | List the class on the role, admit the next route, and read `routing.route_switched` in the run events. `kxm routing report` prints Route switches |
|
|
214
218
|
| `pi_not_authenticated: pi harness not detected (pi_native_impersonation_blocked)` | A Pi agent's model belongs to a vendor with its own harness | Set the agent's native `harness:`, or choose an admitted Pi route whose vendor has none |
|
|
@@ -6,7 +6,7 @@ Move the `kxm` CLI, the hub, the Runtime, and the Claude Code or Pi integrations
|
|
|
6
6
|
|
|
7
7
|
- Protected storage for a full backup; see [Back up and restore KXM](backup-and-restore.md).
|
|
8
8
|
- A window in which the hub, the Runtime supervisor and long-lived workers may stop.
|
|
9
|
-
- The GitHub CLI (`gh`, signed in) if you apply updates with `kxm update --kxm` from the default `github` source,
|
|
9
|
+
- The GitHub CLI (`gh`, signed in) if you apply updates with `kxm update --kxm` from the default `github` source. When `gh` is not installed, that command downloads the same `kxm-<version>.tgz` with curl and still checks the release sha256 before installing. Without a working `kxm` either, use the curl commands in [Update the CLI without gh](#update-the-cli-without-gh).
|
|
10
10
|
|
|
11
11
|
## Check for an update
|
|
12
12
|
|
|
@@ -54,12 +54,27 @@ Use the path that matches how KXM was installed. `kxm update --kxm` applies an u
|
|
|
54
54
|
| Project dependency | `npm install @kontextmind/kxm@latest` in that project |
|
|
55
55
|
| Source checkout | `git pull`, then `npm ci` |
|
|
56
56
|
|
|
57
|
-
`kxm update --kxm` refuses to install a GitHub release that does not publish a SHA-256 digest for its tarball (`release_digest_missing`) or whose download does not match it (`release_digest_mismatch`). Preview the steps first:
|
|
57
|
+
`kxm update --kxm` refuses to install a GitHub release that does not publish a SHA-256 digest for its tarball (`release_digest_missing`) or whose download does not match it (`release_digest_mismatch`). When `gh --version` fails, the download step is `curl --fail --silent --show-error --location` against `https://github.com/kontextmind/kxm/releases/download/v<version>/kxm-<version>.tgz`, and the digest check is unchanged. Preview the steps first:
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
60
|
kxm update --kxm --dry-run
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
+
### Update the CLI without gh
|
|
64
|
+
|
|
65
|
+
On a host that has neither `gh` nor a working `kxm`, download the release tarball and check the digest printed on the GitHub release before installing:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
version=0.7.166
|
|
69
|
+
curl --fail --silent --show-error --location \
|
|
70
|
+
--output "kxm-${version}.tgz" \
|
|
71
|
+
"https://github.com/kontextmind/kxm/releases/download/v${version}/kxm-${version}.tgz"
|
|
72
|
+
sha256sum "kxm-${version}.tgz"
|
|
73
|
+
npm install --global --omit=peer "./kxm-${version}.tgz"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Refuse a tarball whose sha256 does not match the release asset digest.
|
|
77
|
+
|
|
63
78
|
### Update harnesses and plugins
|
|
64
79
|
|
|
65
80
|
Without `--check` or a lone `--kxm`, `kxm update` also runs the native updaters of detected harnesses. Narrow it with a harness id and one scope:
|
|
@@ -76,7 +91,7 @@ kxm update pi --models # refresh Pi model catalogs
|
|
|
76
91
|
|
|
77
92
|
## Start and verify
|
|
78
93
|
|
|
79
|
-
1. Start the hub (or its service), then the Runtime with `kxm runtime start`.
|
|
94
|
+
1. Start the hub (or its service), then the Runtime with `kxm runtime start`. Restart workers too. Do this after the upgrade and again before `kxm hub bind --cloud`, so an older supervisor does not keep a binding it cannot read.
|
|
80
95
|
2. Check `kxm hub view`, `/ready` and `/metrics`.
|
|
81
96
|
3. Check `kxm runtime status` until every project reports `ok` or `no_hub`.
|
|
82
97
|
4. Send one request between two agents and read one Runtime run with `kxm runs status <run-id>`.
|
package/docs/operations.md
CHANGED
|
@@ -88,16 +88,32 @@ kxm hub bind --cloud \
|
|
|
88
88
|
http://127.0.0.1:17331
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
Expected output:
|
|
91
|
+
Expected output when `KXMD_HUB_TOKEN` is set:
|
|
92
92
|
|
|
93
93
|
```text
|
|
94
94
|
bound hub http://127.0.0.1:17331 · remote · health=on · token is not stored
|
|
95
95
|
hub health=true ready=true · remote hub · mode=cloud project=prj_example (.kxm/config.yaml hub.cloud.project) key=env:KXMD_HUB_TOKEN
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
+
With only `--token-command`, and `KXMD_HUB_TOKEN` unset, `kxm hub view` prints
|
|
99
|
+
`key=token-command`. It names the source that would actually supply the token:
|
|
100
|
+
`env:<NAME>` only when that variable is non-empty, otherwise `op:<ref>`,
|
|
101
|
+
`token-command`, `hub-env`, or `missing`. An unset variable is not reported as
|
|
102
|
+
the source.
|
|
103
|
+
|
|
98
104
|
`--token-env` and `--token-command` can be combined. A non-empty variable wins.
|
|
99
105
|
Otherwise the command runs. The command is a program and arguments, not a shell
|
|
100
|
-
pipeline (`|`, `&`, `;`, and redirection are refused).
|
|
106
|
+
pipeline (`|`, `&`, `;`, and redirection are refused). `--token-command` is
|
|
107
|
+
stored only in the machine-wide binding (`hub-binding.cloud.json` under the
|
|
108
|
+
user state root). It is not written to `.kxm/config.yaml`. Config holds
|
|
109
|
+
`key.op` and `key.env` references only.
|
|
110
|
+
|
|
111
|
+
`https://hub.kxmd.dev` is behind an Authentik forward-auth proxy. Clients
|
|
112
|
+
cannot use it: `GET /health` returns the login page (HTTP 200 HTML, or a 302).
|
|
113
|
+
`kxm hub view` treats that as unhealthy (`health=false`, and the JSON `health`
|
|
114
|
+
field is `{ "error": "auth_proxy" }`, not the HTML). `kxm hub bind` refuses
|
|
115
|
+
with `hub_not_kxm` and writes nothing unless you pass `--force`. The supported
|
|
116
|
+
client path is the SSH forward above.
|
|
101
117
|
|
|
102
118
|
<details><summary>PowerShell</summary>
|
|
103
119
|
|
|
@@ -114,8 +130,8 @@ kxm hub view
|
|
|
114
130
|
| | Local bind | `--cloud` bind |
|
|
115
131
|
|---|---|---|
|
|
116
132
|
| Loopback URL | Scope `loopback`. No credential required | Scope `remote`, including an SSH forward |
|
|
117
|
-
| Token stored in
|
|
118
|
-
| Credential later commands send | `KXM_AUTH_TOKEN`, then
|
|
133
|
+
| Token stored in the binding | No | No. `hub-binding.cloud.json` names `tokenEnv` and/or `tokenCommand`. `hub-binding.json` stays a three-key local record, or is omitted, so a 0.7.159 reader does not throw |
|
|
134
|
+
| Credential later commands send | Agent commands use `KXM_AUTH_TOKEN`, then `hub.local` `key.env` / `key.op`, then this project's saved project token. They never use the hub-env admin token (`project_token_missing`). `kxm hub view` and `kxm tenant status` may use the admin token | The active mode's key reference, then the binding's named source. Hub-env is not a fallback |
|
|
119
135
|
| Missing source | Agent commands report `project_token_missing` and name the project id that was sent | `cloud_token_missing` or `cloud_token_command_failed`. The local admin token is not sent |
|
|
120
136
|
| `kxm hub start` from an extension | May start a local hub | Does not start a local hub when the forward is down (`cloud_hub_unreachable`) |
|
|
121
137
|
|
|
@@ -124,6 +140,47 @@ kxm hub view
|
|
|
124
140
|
all use that source. `kxm agent worker` puts `KXM_AUTH_TOKEN` in the child
|
|
125
141
|
process environment only. It does not write the token to disk.
|
|
126
142
|
|
|
143
|
+
A local bind does not give agents the admin token from hub-env. Give them a
|
|
144
|
+
project token in one of these ways:
|
|
145
|
+
|
|
146
|
+
- On the client, export `KXM_AUTH_TOKEN` to that project's token, or set
|
|
147
|
+
`hub.local.key.env` / `hub.local.key.op` in `.kxm/config.yaml`.
|
|
148
|
+
- On the hub, map the project id in `hub.projects` (an `op://` reference or an
|
|
149
|
+
environment variable name) or in `KXM_PROJECT_TOKENS`, keyed by the same id
|
|
150
|
+
the client sends.
|
|
151
|
+
|
|
152
|
+
### Where to store tokens
|
|
153
|
+
|
|
154
|
+
Keep hub admin and project tokens in 1Password and point KXM at `op://` references
|
|
155
|
+
(`--key-op`, `key.op`, or `--token-command "op read op://..."`). Do not paste the
|
|
156
|
+
token into `.kxm/config.yaml`, `hub-binding.json`, or `hub-binding.cloud.json`.
|
|
157
|
+
|
|
158
|
+
A hub host that has no `op` binary should take the token from the environment
|
|
159
|
+
or from a systemd credentials file. The unit in
|
|
160
|
+
[Supervise the hub and Runtime](operations/deploy.md#the-hub) loads
|
|
161
|
+
`EnvironmentFile=/etc/kxm/hub.env` (mode 0600) for `KXM_AUTH_TOKEN` and
|
|
162
|
+
`KXM_PROJECT_TOKENS`.
|
|
163
|
+
|
|
164
|
+
### Restart after an upgrade, and before a cloud bind
|
|
165
|
+
|
|
166
|
+
Restart the Runtime supervisor, the hub, and workers after upgrading and before
|
|
167
|
+
`kxm hub bind --cloud`:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
kxm runtime stop
|
|
171
|
+
kxm hub stop
|
|
172
|
+
kxm runtime start
|
|
173
|
+
kxm hub start
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
A 0.7.159 supervisor treats any extra key in `hub-binding.json` as
|
|
177
|
+
`malformed hub binding` and stops syncing. This release keeps cloud fields in
|
|
178
|
+
`hub-binding.cloud.json` and leaves `hub-binding.json` as a three-key local
|
|
179
|
+
record, or omits it. An older reader then keeps the local hub instead of
|
|
180
|
+
throwing. A binding newer than this build is ignored with a warning, and sync
|
|
181
|
+
continues as `no_hub` rather than stalling. Processes that were already running
|
|
182
|
+
keep the binding they loaded at start, so restart them after the upgrade.
|
|
183
|
+
|
|
127
184
|
The hub project id is the same value everywhere: `--project` or `KXM_PROJECT`,
|
|
128
185
|
then the active mode's `project` in `.kxm/config.yaml`, then the `id` in
|
|
129
186
|
`.kxm/project.yaml`, then `package.json` `name`, then the directory name.
|
|
@@ -147,7 +204,8 @@ hub:
|
|
|
147
204
|
op: op://Private/kxm/local-project-token
|
|
148
205
|
env: KXM_LOCAL_PROJECT_TOKEN
|
|
149
206
|
cloud:
|
|
150
|
-
|
|
207
|
+
# Clients use an SSH forward. https://hub.kxmd.dev is an Authentik login page.
|
|
208
|
+
url: http://127.0.0.1:17331
|
|
151
209
|
project: prj_example
|
|
152
210
|
key:
|
|
153
211
|
op: op://Private/kxmd/project-token
|
|
@@ -167,7 +225,8 @@ with `hub_config_invalid`.
|
|
|
167
225
|
`kxm hub bind` and `kxm hub bind --cloud` write the mode, URL, project id, and
|
|
168
226
|
key reference. `--key-op` is the `op://` reference for either mode.
|
|
169
227
|
`--token-env` names the variable for either mode. `--token-command` stays
|
|
170
|
-
cloud-only
|
|
228
|
+
cloud-only, and only in `hub-binding.cloud.json`, not in this file.
|
|
229
|
+
`kxm hub view` prints the mode, URL, project id, and key source.
|
|
171
230
|
It does not print the token. `kxm hub unbind` removes the binding and
|
|
172
231
|
`hub.mode`, and leaves the `local` and `cloud` blocks in place.
|
|
173
232
|
|
|
@@ -185,7 +244,8 @@ send the `.kxm/project.yaml` id and the hub has no token for it.
|
|
|
185
244
|
kxm hub unbind
|
|
186
245
|
```
|
|
187
246
|
|
|
188
|
-
Unbind deletes `hub-binding.json` and
|
|
247
|
+
Unbind deletes `hub-binding.json` and `hub-binding.cloud.json`, and clears
|
|
248
|
+
`hub.mode` in `.kxm/config.yaml`.
|
|
189
249
|
The `local` and `cloud` blocks stay, so the next bind can switch mode again.
|
|
190
250
|
It does not delete hub-env, and it does not close the SSH forward. Stop the
|
|
191
251
|
forward by ending the `ssh -N` session.
|
|
@@ -200,6 +260,9 @@ forward by ending the `ssh -N` session.
|
|
|
200
260
|
| `cloud_token_command_failed` | `op` exited non-zero, timed out, or printed more than one line | Run the same command in a terminal and sign in to 1Password. Do not paste the token into the binding |
|
|
201
261
|
| Clients through one SSH host get locked out together | The hub rate-limits by agent id, otherwise by source address. Every forward from one SSH session shares `127.0.0.1` on the hub. `sshd` `MaxStartups` and `MaxSessions` can refuse new forwards first | Give each long-lived agent its own name. Raise the SSH limits on that host if many people share one jump host. Do not point two tenants at one hub |
|
|
202
262
|
| `kxm hub view` says `loopback` for the forward | `--cloud` was omitted | Bind again with `--cloud`. `KXM_SERVER_URL` overrides the binding URL and is labeled on its own |
|
|
263
|
+
| `hub_not_kxm`, or `kxm hub view` prints `auth proxy` with `health=false` | The URL is an Authentik (or other) login page, or a 30x redirect, not a kxm hub. `https://hub.kxmd.dev` is that case | Bind `http://127.0.0.1:17331` through the SSH forward. `--force` writes the binding anyway and is not a working client path |
|
|
264
|
+
| `key=env:KXMD_HUB_TOKEN` while that variable is unset | An older `kxm hub view` named the configured variable even when it was empty | Upgrade. The line names `token-command`, `op:<ref>`, `hub-env`, or `missing` for the source that actually supplies the token |
|
|
265
|
+
| `malformed hub binding` and sync stops after a cloud bind | A supervisor older than this release read cloud fields in `hub-binding.json` | Upgrade, then restart the supervisor, hub, and workers before binding `--cloud` again |
|
|
203
266
|
|
|
204
267
|
## Next steps
|
|
205
268
|
|
|
@@ -477,12 +477,12 @@ Starts, inspects, and stops the local KXM hub, and binds this machine to a hub.
|
|
|
477
477
|
kxm hub view
|
|
478
478
|
```
|
|
479
479
|
|
|
480
|
-
Calls `GET /health` and `GET /ready` on the target hub and reports whether the URL is loopback or remote, plus the mode, project id, and key source in effect. The key source is
|
|
480
|
+
Calls `GET /health` and `GET /ready` on the target hub and reports whether the URL is loopback or remote, plus the mode, project id, and key source in effect. A probe counts only when the response is JSON (`application/json`, or `text/plain` with a JSON object) of the hub shape: `/health` is `{ "ok": true, "agents": <number> }` and `/ready` is `{ "ok": true, "storage": "sqlite"|"memory" }`. An HTTP 200 HTML login page, or a 30x redirect, is not healthy. The JSON `health` and `ready` fields then hold `{ "error": "auth_proxy" }` and never the HTML. The key source is the one that would supply the token: `env:<NAME>` only when that variable is non-empty, `op:<ref>`, `token-command`, `hub-env`, or `missing`. The token is not printed.
|
|
481
481
|
|
|
482
482
|
No command-specific options.
|
|
483
483
|
|
|
484
484
|
- Needs a hub to succeed. Reads only.
|
|
485
|
-
- JSON keys: `target` (`url`, `scope`, and `source: "env"` when `KXM_SERVER_URL` overrides a binding), `identity` (`mode`, `modeSource`, `url`, `urlSource`, `project`, `projectSource`, `keySource`), `health`, `ready`. An unreachable hub reports `{"error":"hub_unreachable"}` for both probes.
|
|
485
|
+
- JSON keys: `target` (`url`, `scope`, and `source: "env"` when `KXM_SERVER_URL` overrides a binding), `identity` (`mode`, `modeSource`, `url`, `urlSource`, `project`, `projectSource`, `keySource`), `health`, `ready`. An unreachable hub reports `{"error":"hub_unreachable"}` for both probes. An auth proxy or redirect reports `{"error":"auth_proxy"}`.
|
|
486
486
|
- Exit 0 when both probes succeed, 1 otherwise. A cloud mode with no resolvable key exits 2 with `cloud_token_missing`.
|
|
487
487
|
|
|
488
488
|
```bash
|
|
@@ -569,15 +569,16 @@ kxm hub stop --wait-ms 8000 --json
|
|
|
569
569
|
### `kxm hub bind`
|
|
570
570
|
|
|
571
571
|
```text
|
|
572
|
-
kxm hub bind <url> [--cloud] [--token-env <name>] [--token-command <command>] [--key-op <op://vault/item/field>]
|
|
572
|
+
kxm hub bind <url> [--cloud] [--token-env <name>] [--token-command <command>] [--key-op <op://vault/item/field>] [--force]
|
|
573
573
|
```
|
|
574
574
|
|
|
575
|
-
Binds this machine to a running hub by writing
|
|
575
|
+
Binds this machine to a running hub by writing the binding under the user state root and the non-secret endpoint (mode, URL, project id, key reference) into `.kxm/config.yaml`, then probes the hub's health for up to 300 ms. A local bind writes `hub-binding.json` (`schema`, `url`, `boundAt` only). A `--cloud` bind writes `hub-binding.cloud.json` and leaves a three-key local file in place, or omits `hub-binding.json`, so a 0.7.159 reader does not throw `malformed hub binding` and stop sync. `--token-command` is stored only in that cloud file, not in `.kxm/config.yaml`. Every hub client uses that endpoint when `KXM_SERVER_URL` is unset. The token is never written.
|
|
576
576
|
|
|
577
577
|
- Arguments: `<url>`, Hub base URL (http or https).
|
|
578
578
|
- A URL with credentials, a query, a fragment, or a scheme other than http or https fails with `hub_url_invalid` (exit 2).
|
|
579
579
|
- A remote (non-loopback) URL is refused with `hub_bind_unauthenticated` (exit 2, `nextAction: "export_kxm_auth_token"`) unless a credential for the current project resolves from `KXM_AUTH_TOKEN` or the persisted `hub-env.json`. A malformed record fails with `hub_credential_unreadable` (exit 2). A loopback URL without `--cloud` still binds with no credential.
|
|
580
580
|
- `--cloud` marks the binding remote even when the URL is a loopback forward. It requires `--token-env`, `--token-command`, `--key-op`, or a combination. The token is not written. A non-empty variable wins; otherwise an `op://` reference is read with `op read`, or the command runs. `--token-command` without `--cloud` fails with `cloud_flag_required`. `--token-env` and `--key-op` are also valid on a local bind and are stored only as references in config. A missing cloud source later fails with `cloud_token_missing` and does not fall back to hub-env. See [Cross-box peer attach](../operations.md#cross-box-peer-attach).
|
|
581
|
+
- The probe accepts a kxm `/health` body. A timeout (`health=unknown`) or a connection failure (`health=off`) still writes the binding. An HTML login page or a 30x redirect is `hub_not_kxm` (exit 2, `kind` `auth_proxy` or `redirect`) and writes nothing. The error names an auth proxy or a redirect. `--force` writes anyway. `https://hub.kxmd.dev` is an Authentik login page; clients use the SSH forward at `http://127.0.0.1:17331`.
|
|
581
582
|
- Mutates the binding file and `.kxm/config.yaml`. `--dry-run` validates and prints the plan without writing.
|
|
582
583
|
- JSON keys: `url`, `scope`, `file`, `configFile`, `project`, `health` (`on`, `off`, or `unknown`), `probeMs`. A cloud bind also returns `cloud`, and `tokenEnv` or `tokenCommand` when set.
|
|
583
584
|
|
|
@@ -984,7 +985,20 @@ Checks for or applies a KXM operator package update, and runs the native updater
|
|
|
984
985
|
|
|
985
986
|
- Arguments: `[harness]`, Harness id (default: every detected harness).
|
|
986
987
|
- `--check` cannot be combined with any other update flag or a harness (exit 2, `scope_conflict`), and at most one of `--self`, `--extensions`, `--models` is allowed (exit 2).
|
|
987
|
-
- From a source checkout, `--check` reports the running version without network access, and `--kxm` is refused (exit 2, `install_kind_source`) with an instruction to `git pull`. Only npm-global installs can apply `--kxm`; other install kinds exit 2 with `install_kind_<kind>`. A GitHub release must publish a sha256 digest for `kxm-<version>.tgz` or the install fails closed (`release_digest_missing`, `release_digest_mismatch`).
|
|
988
|
+
- From a source checkout, `--check` reports the running version without network access, and `--kxm` is refused (exit 2, `install_kind_source`) with an instruction to `git pull`. Only npm-global installs can apply `--kxm`; other install kinds exit 2 with `install_kind_<kind>`. A GitHub release must publish a sha256 digest for `kxm-<version>.tgz` or the install fails closed (`release_digest_missing`, `release_digest_mismatch`). When `gh` is missing, the github source downloads that same asset with `curl --fail --silent --show-error --location` and still verifies the digest before `npm install -g`.
|
|
989
|
+
|
|
990
|
+
On a host with neither `gh` nor a working `kxm`, download and check it yourself:
|
|
991
|
+
|
|
992
|
+
```bash
|
|
993
|
+
version=0.7.166
|
|
994
|
+
curl --fail --silent --show-error --location \
|
|
995
|
+
--output "kxm-${version}.tgz" \
|
|
996
|
+
"https://github.com/kontextmind/kxm/releases/download/v${version}/kxm-${version}.tgz"
|
|
997
|
+
# Compare with the sha256 digest published on the GitHub release asset.
|
|
998
|
+
sha256sum "kxm-${version}.tgz"
|
|
999
|
+
npm install --global --omit=peer "./kxm-${version}.tgz"
|
|
1000
|
+
```
|
|
1001
|
+
|
|
988
1002
|
- Settings come only from `update.yaml` under the user state root (`auto: true` enables auto-apply); a project `.kxm/update.yaml` is ignored with a warning.
|
|
989
1003
|
- Without `--check` or a lone `--kxm`, KXM probes harnesses (as `harness list` does) and runs each updater for the selected scope. An unknown harness id exits 2 (`unknown_harness` step); a failed step exits 1.
|
|
990
1004
|
- Honors `--dry-run`: steps are planned, not run, and the cached update notice is not refreshed.
|
|
@@ -1612,7 +1626,7 @@ Create a KXM run without executing steps. The run pins the project's `homeRuntim
|
|
|
1612
1626
|
- Refuses `--workspace` (exit 2, `workspace_option_unsupported`).
|
|
1613
1627
|
- Needs a KXM project. Starts and uses the Runtime; no hub needed. Honors `--dry-run`, which validates the project and prints the plan without starting the supervisor.
|
|
1614
1628
|
- JSON keys: `idempotent`, `run` (`runId`, `homeRuntimeId`, `status`, `configRevision`), `supervisor` (`runtimeId`, `port`, `started`), and `execution` (`status: not_started`, `mode: live`, `defaultHarness`, `authentication: not_checked`, `prerequisites`, `nextSteps`). Dry run: `projectRoot`, `workflowId`, `configRevision`, `defaultHarness`, `prerequisites`. The obsolete `phase: pre-3a` field is no longer returned.
|
|
1615
|
-
- Errors: `workflow_required` (exit 2), `project_required`, `run_workflow_unknown`, `brief_and_prompt`, `brief_unreadable`, `lane_missing`, `lane_run_open`, `run_failed` with `issues` (any invalid file in the project fails the load, for example `gate_outcome_impossible`), `run_io_failed` (exit 1).
|
|
1629
|
+
- Errors: `workflow_required` (exit 2), `project_required`, `run_workflow_unknown`, `brief_and_prompt`, `brief_unreadable`, `lane_missing`, `lane_run_open`, `run_failed` with `issues` (any invalid file in the project fails the load, for example `gate_outcome_impossible`), `run_io_failed` (exit 1). `project_home_conflict` means this checkout is not the registered home for that project id: a different repository already owns it, the home runtime is immutable, or the primary checkout is already the home row. Use the original checkout, or a worktree of that repository. Do not copy the project id into an unrelated clone, and do not delete the database. `runtime_schema_newer` means the store was written by a newer release than this build. Upgrade KXM. Do not delete the database.
|
|
1616
1630
|
- The `default` workflow that `kxm init` writes does not set `limits.maxAgentTimeMs`, so it can be driven. A workflow that sets that limit is created, but `kxm runs drive` refuses it with `run_handoff_required` (`limit_unsupported`); projects from older `kxm init` templates carry it on `default`.
|
|
1617
1631
|
|
|
1618
1632
|
```bash
|
|
@@ -1826,6 +1840,7 @@ No command-specific options.
|
|
|
1826
1840
|
- Reads only. Never starts the supervisor.
|
|
1827
1841
|
- JSON keys: `running`, `runtimeId`, `pid`, `port`, `state`, `heartbeatAt`, `startedAt`, `sync`.
|
|
1828
1842
|
- Exit 0 when running, 1 when not (the JSON still says `ok: true`).
|
|
1843
|
+
- When the supervisor process is up but `GET /v1/sync/status` fails, the text line is `sync: the supervisor is running but did not answer /v1/sync/status`. The usual causes are a hung supervisor, a token the status command does not hold, or a supervisor started before an upgrade. `kxm runtime stop` and `kxm runtime start` replace it. A binding this build cannot read is a warning and `no_hub`, not a stalled sync; restart after upgrading and before a cloud bind. See [Check sync status](../operations/runtime-sync.md#check-sync-status).
|
|
1829
1844
|
|
|
1830
1845
|
```bash
|
|
1831
1846
|
kxm runtime status
|
|
@@ -337,7 +337,7 @@ with `retired_agent_routing_fields`.
|
|
|
337
337
|
| `skills` | Unique identifiers, at most 64 | Optional | Skill names granted to the agent |
|
|
338
338
|
| `instructions` | String, at most 16,000 characters | Optional | Not read by any code path yet. Step `instructions` are what reach the prompt. |
|
|
339
339
|
| `executor` | `local`, `ssh`, or `exe-dev` | Optional | Loader (`executor_unknown`); recorded in the executor-policy revision; no dispatch path selects an executor from it yet |
|
|
340
|
-
| `tools.preset` | `coordinator`, `read-only`, `workspace-writer`, or `tests-writer` | Optional | Loader (`tool_preset_unknown`): the preset must be registered.
|
|
340
|
+
| `tools.preset` | `coordinator`, `read-only`, `workspace-writer`, or `tests-writer` | Optional | Loader (`tool_preset_unknown`): the preset must be registered. `coordinator` and `read-only` select the read-only one-shot profile. `workspace-writer` and `tests-writer` select the edit profile. An agent preset may only narrow the role. A wider preset is `tool_preset_exceeds_role` at load. |
|
|
341
341
|
| `tools.allow`, `tools.deny` | Unique identifiers, at most 128 each | Optional | A tool in both lists is `tool_policy_contradiction`; steps may only narrow the ceiling |
|
|
342
342
|
| `defaultRepositoryAccess` | `none`, `read`, or `write` | Optional; the ceiling is `none` when absent | Loader: access ceiling for repositories not listed in `repositories` |
|
|
343
343
|
| `repositories` | Map of repository ID to `none`, `read`, or `write`; at most 64 | Optional | Loader: per-repository access ceiling; IDs must be declared (`repository_unknown`) |
|
|
@@ -349,18 +349,30 @@ with `retired_agent_routing_fields`.
|
|
|
349
349
|
| `session.reuse` | `compatible-run-scope` | Optional | Not read by any code path yet |
|
|
350
350
|
| `session.maxIdleMs` | Integer, 0 to 31,536,000,000 | Optional | Not read by any code path yet |
|
|
351
351
|
|
|
352
|
-
Tool presets are names checked against a registered list
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
`
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
352
|
+
Tool presets are names checked against a registered list, then mapped onto
|
|
353
|
+
the harness one-shot profiles in `plugins/kxm/src/harness.ts`. `coordinator`
|
|
354
|
+
and `read-only` use the read-only argument set (`READ_ONLY_ONESHOT_ARGS`).
|
|
355
|
+
`workspace-writer` and `tests-writer` use the audited writer set
|
|
356
|
+
(`WRITER_ONESHOT_ARGS`), which exists only for `pi` (`-a` with extensions,
|
|
357
|
+
skills, prompt templates and sessions off) and `grok` (`--always-approve`
|
|
358
|
+
with subagents and web search off). Both approve every tool call, shell
|
|
359
|
+
commands included, and neither confines the process to the checkout.
|
|
360
|
+
|
|
361
|
+
Dispatch permission is the narrowest of the role `permission`, the preset
|
|
362
|
+
profile (the role preset, then the agent preset), and the step's repository
|
|
363
|
+
access (`write` is edit; `read` and `none` are read-only). A preset cannot
|
|
364
|
+
widen a role. An agent preset that is wider fails load with
|
|
365
|
+
`tool_preset_exceeds_role`, and dispatch refuses that file again with
|
|
366
|
+
`step_unsupported` (field `tools.preset`) when the process already loaded
|
|
367
|
+
it. A write step whose resolved profile is read-only is `step_unsupported`
|
|
368
|
+
(field `permission`) before the producer starts. The detail names the role
|
|
369
|
+
permission and the step access. A live write that does resolve to edit
|
|
370
|
+
still hands off on a harness with no audited writer set; see
|
|
362
371
|
[Steps the Runtime does not execute yet](#steps-the-runtime-does-not-execute-yet).
|
|
363
372
|
|
|
373
|
+
`tools.allow` and `tools.deny` apply to the MCP surface through
|
|
374
|
+
`enforceToolPolicy` in `plugins/kxm/src/commands.ts`.
|
|
375
|
+
|
|
364
376
|
Example (the shape `kxm init` writes for `writer`):
|
|
365
377
|
|
|
366
378
|
```yaml
|
|
@@ -394,7 +406,7 @@ Runtime cannot reach the `antigravity` Pi provider yet. `kxm run` and the
|
|
|
394
406
|
Runtime read the agents. `kxm trust` diffs them.
|
|
395
407
|
|
|
396
408
|
Error codes: `retired_agent_routing_fields`, `executor_unknown`,
|
|
397
|
-
`tool_preset_unknown`, `tool_policy_contradiction`, `repository_unknown`, and
|
|
409
|
+
`tool_preset_unknown`, `tool_preset_exceeds_role`, `tool_policy_contradiction`, `repository_unknown`, and
|
|
398
410
|
the path codes under
|
|
399
411
|
[Rules shared by the project bundle](#rules-shared-by-the-project-bundle).
|
|
400
412
|
|
|
@@ -1311,6 +1323,8 @@ no recorded cost is never ready.
|
|
|
1311
1323
|
```yaml
|
|
1312
1324
|
# .kxm/config.yaml (project scope) or ~/.config/kxm/config.yaml (user scope).
|
|
1313
1325
|
# The project file wins. Key fields are references, never tokens.
|
|
1326
|
+
# --token-command is not a config field. It lives only in the machine-wide
|
|
1327
|
+
# hub-binding.cloud.json written by `kxm hub bind --cloud`.
|
|
1314
1328
|
hub:
|
|
1315
1329
|
autoStart: background # background | off
|
|
1316
1330
|
mode: local # local | cloud
|
|
@@ -1321,7 +1335,8 @@ hub:
|
|
|
1321
1335
|
op: op://Private/kxm/local-project-token
|
|
1322
1336
|
env: KXM_LOCAL_PROJECT_TOKEN
|
|
1323
1337
|
cloud:
|
|
1324
|
-
|
|
1338
|
+
# Clients use an SSH forward. https://hub.kxmd.dev is an Authentik login page.
|
|
1339
|
+
url: http://127.0.0.1:17331
|
|
1325
1340
|
project: prj_example
|
|
1326
1341
|
key:
|
|
1327
1342
|
op: op://Private/kxmd/project-token
|
package/docs/start/install.md
CHANGED
|
@@ -8,7 +8,7 @@ KXM has three parts you can install: the `kxm` command-line tool, the Claude Cod
|
|
|
8
8
|
- Git.
|
|
9
9
|
- Claude Code, if you want the plugin.
|
|
10
10
|
- Pi, if you want Pi agents. Install it with `npm install --global @earendil-works/pi-coding-agent` and sign in to a model provider as the [Pi documentation](https://pi.dev/docs/latest) describes.
|
|
11
|
-
- The GitHub CLI (`gh`), only if you plan to update with `kxm update --kxm
|
|
11
|
+
- The GitHub CLI (`gh`), only if you plan to update with `kxm update --kxm` from the GitHub source. When `gh` is missing, that command falls back to curl and still checks the release checksum. The manual curl commands are in [Upgrade KXM](../operations/upgrade.md#update-the-cli-without-gh).
|
|
12
12
|
|
|
13
13
|
## Choose what to install
|
|
14
14
|
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "kxm",
|
|
4
4
|
"displayName": "KXM",
|
|
5
|
-
"version": "0.7.
|
|
5
|
+
"version": "0.7.169",
|
|
6
6
|
"description": "Headless multi-agent orchestration, durable workflows, and a live operator dashboard for Pi and Claude Code",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "KontextMind",
|