@kontextmind/kxm 0.7.165 → 0.7.167

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 (41) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +16 -0
  3. package/docs/README.md +1 -0
  4. package/docs/architecture/hosted-direction.md +9 -4
  5. package/docs/architecture/inventory.md +1 -0
  6. package/docs/concepts/trust-model.md +1 -1
  7. package/docs/contributing/decisions.md +153 -0
  8. package/docs/contributing/learnings.md +54 -53
  9. package/docs/contributing/operating-rules.md +19 -6
  10. package/docs/glossary.md +2 -2
  11. package/docs/operations/troubleshooting.md +2 -2
  12. package/docs/operations.md +62 -8
  13. package/docs/reference/cli-reference.md +11 -11
  14. package/docs/reference/config-reference.md +36 -11
  15. package/docs/reference/configuration.md +2 -2
  16. package/docs/reference/tools.md +1 -1
  17. package/docs/start/quickstart-claude-code.md +2 -2
  18. package/package.json +1 -1
  19. package/plugins/kxm/.claude-plugin/plugin.json +1 -1
  20. package/plugins/kxm/README.md +3 -3
  21. package/plugins/kxm/dist/claude-hook.js +417 -66
  22. package/plugins/kxm/dist/cli.js +1399 -900
  23. package/plugins/kxm/dist/extension.js +399 -64
  24. package/plugins/kxm/dist/mcp-server.js +622 -135
  25. package/plugins/kxm/dist/runtime-supervisor.js +668 -166
  26. package/plugins/kxm/dist/runtime.js +713 -211
  27. package/plugins/kxm/dist/server.js +466 -58
  28. package/plugins/kxm/package.json +1 -1
  29. package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +15 -7
  30. package/plugins/kxm/src/cli/hub.ts +80 -21
  31. package/plugins/kxm/src/cli/types.ts +8 -1
  32. package/plugins/kxm/src/cli.ts +41 -7
  33. package/plugins/kxm/src/config.ts +246 -3
  34. package/plugins/kxm/src/extension.ts +8 -7
  35. package/plugins/kxm/src/hub-autostart.ts +20 -0
  36. package/plugins/kxm/src/hub-env.ts +83 -31
  37. package/plugins/kxm/src/hub-identity.ts +337 -0
  38. package/plugins/kxm/src/mcp-server.ts +17 -15
  39. package/plugins/kxm/src/project-name.ts +6 -47
  40. package/plugins/kxm/src/server.ts +22 -4
  41. package/scripts/kxm-hub.mjs +5 -0
@@ -477,20 +477,20 @@ 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.
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 an environment variable name or an `op://` reference. 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), `health`, `ready`. An unreachable hub reports `{"error":"hub_unreachable"}` for both probes.
486
- - Exit 0 when both probes succeed, 1 otherwise.
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.
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
489
489
  kxm hub view
490
490
  ```
491
491
 
492
492
  ```text
493
- hub health=true ready=true · loopback hub
493
+ hub health=true ready=true · loopback hub · mode=local project=prj_example (.kxm/project.yaml id) key=hub-env
494
494
  ```
495
495
 
496
496
  ```bash
@@ -569,17 +569,17 @@ 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>]
572
+ kxm hub bind <url> [--cloud] [--token-env <name>] [--token-command <command>] [--key-op <op://vault/item/field>]
573
573
  ```
574
574
 
575
- Binds this machine to a running hub by writing `hub-binding.json` under the user state root, then probes the hub's health for up to 300 ms. Every hub client uses the binding when `KXM_SERVER_URL` is unset.
575
+ Binds this machine to a running hub by writing `hub-binding.json` 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. 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
- - `--cloud` marks the binding remote even when the URL is a loopback forward. It requires `--token-env`, `--token-command`, or both. The token is not written. A non-empty variable wins; otherwise the command runs. Source flags without `--cloud` fail with `cloud_flag_required`. A missing 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
- - Mutates the binding file. `--dry-run` validates and prints the plan without writing.
582
- - JSON keys: `url`, `scope`, `file`, `health` (`on`, `off`, or `unknown`), `probeMs`. A cloud bind also returns `cloud`, and `tokenEnv` or `tokenCommand` when set.
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
+ - Mutates the binding file and `.kxm/config.yaml`. `--dry-run` validates and prints the plan without writing.
582
+ - 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
583
 
584
584
  ```bash
585
585
  kxm hub bind http://127.0.0.1:7331 --dry-run
@@ -603,7 +603,7 @@ kxm hub bind https://hub.example.com --dry-run --json
603
603
  kxm hub unbind
604
604
  ```
605
605
 
606
- Removes this machine's hub binding, including a malformed binding record.
606
+ Removes this machine's hub binding, including a malformed binding record, and clears `hub.mode` in `.kxm/config.yaml`. The `hub.local` and `hub.cloud` blocks stay.
607
607
 
608
608
  No command-specific options.
609
609
 
@@ -2469,7 +2469,7 @@ Captured without a GitHub token. With `GITHUB_TOKEN` set, the same command polls
2469
2469
 
2470
2470
  ## `kxm peer`
2471
2471
 
2472
- Peer agent messaging through the hub. Each invocation connects to the hub as a short-lived agent named `KXM_AGENT_NAME` (default `cli-<pid>`) in project `KXM_PROJECT` (default: the `package.json` name, else the directory name), using `KXM_AUTH_TOKEN`, else this project's saved project token from `hub-env.json`. It never uses the persisted admin token: with neither, the command exits 2 with `project_token_missing` (`nextAction: "export_kxm_auth_token"`) before contacting the hub. The `kxm workflow` agent verbs (`checkpoint`, `record`, `wait`, `get`, `list`) connect the same way. That agent appears in `peer list` and the dashboard. Every subcommand accepts `--payload <json>` with the tool's fields as one object; explicit flags override it. Tool policy from `KXM_ATTEMPT_TOKEN`, `KXM_SESSION_TOKEN`, or the on-disk session token is enforced first (`tool_policy_denied`, `session_token_invalid`, `attempt_token_invalid`).
2472
+ Peer agent messaging through the hub. Each invocation connects to the hub as a short-lived agent named `KXM_AGENT_NAME` (default `cli-<pid>`). The project id is `--project`, then `KXM_PROJECT`, then the active mode's `project` in `.kxm/config.yaml`, then the `id` in `.kxm/project.yaml`, then the `package.json` name, then the directory name. The token is `KXM_AUTH_TOKEN`, else the active mode's key reference, else this project's saved project token from `hub-env.json`. It never uses the persisted admin token: with none of those, the command exits 2 with `project_token_missing` (`nextAction: "configure_hub_project"`) and names the project id and where it came from, before contacting the hub. The `kxm workflow` agent verbs (`checkpoint`, `record`, `wait`, `get`, `list`) connect the same way. That agent appears in `peer list` and the dashboard. Every subcommand accepts `--payload <json>` with the tool's fields as one object; explicit flags override it. Tool policy from `KXM_ATTEMPT_TOKEN`, `KXM_SESSION_TOKEN`, or the on-disk session token is enforced first (`tool_policy_denied`, `session_token_invalid`, `attempt_token_invalid`).
2473
2473
 
2474
2474
  All subcommands need a hub, honor `--dry-run` (printing the parsed `args` without connecting), print the hub's result object on success, and print `{"ok":false,"error":"command_failed","detail":"..."}` with exit 1 on failure. Malformed `--payload` exits 2 with `invalid_payload`.
2475
2475
 
@@ -1255,20 +1255,28 @@ in `plugins/kxm/src/config.ts`, then the user file
1255
1255
  `$KXM_USER_CONFIG_DIR/config.yaml` (default `~/.config/kxm/config.yaml`), then
1256
1256
  the project file `.kxm/config.yaml` in the current directory. Later layers win
1257
1257
  key by key; arrays are replaced, not merged. The files need no `schema` key.
1258
- Nothing validates keys or values except `hub.autoStart` and the `improvement.*`
1259
- keys, which fall back to their defaults field by field (see the table), but a file
1260
- that is not valid YAML makes every `kxm config` command fail. `kxm improve` loads
1261
- the project file from its project root (the current directory's Git root when it
1262
- holds `.kxm/project.yaml`) rather than from the current directory.
1263
-
1264
- Two groups of keys change behavior today: `hub.autoStart`, and the `improvement.*`
1265
- keys that shape the report `kxm improve` prints. The **Read by** column lists every
1266
- reader found in `plugins/kxm/src`, `scripts/`, and `packages/`; the `kxm config`
1267
- commands themselves are not counted.
1258
+ `hub.autoStart` and the `improvement.*` keys fall back to their defaults field
1259
+ by field (see the table). `hub.mode`, `hub.local`, `hub.cloud`, and
1260
+ `hub.projects` are validated: a literal token is refused with
1261
+ `hub_config_invalid`, and a mode other than `local` or `cloud` is refused. A
1262
+ file that is not valid YAML makes every `kxm config` command fail. `kxm improve`
1263
+ loads the project file from its project root (the current directory's Git root
1264
+ when it holds `.kxm/project.yaml`) rather than from the current directory.
1265
+
1266
+ The keys that change behavior are the `hub` section below and the
1267
+ `improvement.*` keys that shape the report `kxm improve` prints. Hub URL, mode,
1268
+ project id, and key reference live here rather than in `.kxm/project.yaml`
1269
+ because `hub.autoStart` was already this file's hub setting, and
1270
+ `project.yaml` stays the stable hashed project id. The **Read by** column lists
1271
+ every reader found in `plugins/kxm/src`, `scripts/`, and `packages/`; the
1272
+ `kxm config` commands themselves are not counted.
1268
1273
 
1269
1274
  | Key | Type and allowed values | Default | Read by |
1270
1275
  |---|---|---|---|
1271
1276
  | `hub.autoStart` | `background` or `off`; any other value falls back to `background` | `background` | The Pi extension on load (`plugins/kxm/src/extension.ts`, `hub-autostart.ts`) |
1277
+ | `hub.mode` | `local` or `cloud`. Any other value is `hub_config_invalid`. Unset means local unless a cloud binding exists | unset | Every hub client (`hub-identity.ts`): CLI, Pi extension, MCP server, dash, and `kxm agent worker` |
1278
+ | `hub.local`, `hub.cloud` | `url` (http or https, no userinfo, query, or fragment), `project` (one line, no spaces), and `key` | unset | The same clients, for the active mode. `project` defaults to the `.kxm/project.yaml` id when omitted |
1279
+ | `hub.local.key`, `hub.cloud.key`, `hub.projects.<id>` | `op` is `op://vault/item/field`. `env` is an environment variable name. A string, or a field named like a token, is refused | unset | Clients resolve the active mode's key at use time. The hub process resolves `hub.projects` in memory (`server.ts`). Neither writes the resolved token |
1272
1280
  | `user.name`, `user.email` | String | none | Not read by any code path yet |
1273
1281
  | `user.preferredHarness`, `user.preferredModel` | String | none | Not read by any code path yet |
1274
1282
  | `user.preferredCritics` | Array of strings | `[reviewer-arch, reviewer-cli]` | Not read by any code path yet |
@@ -1302,9 +1310,26 @@ no recorded cost is never ready.
1302
1310
 
1303
1311
  ```yaml
1304
1312
  # .kxm/config.yaml (project scope) or ~/.config/kxm/config.yaml (user scope).
1305
- # Only hub.autoStart and improvement.* change behavior today.
1313
+ # The project file wins. Key fields are references, never tokens.
1306
1314
  hub:
1307
1315
  autoStart: background # background | off
1316
+ mode: local # local | cloud
1317
+ local:
1318
+ url: http://127.0.0.1:7331
1319
+ project: prj_example
1320
+ key:
1321
+ op: op://Private/kxm/local-project-token
1322
+ env: KXM_LOCAL_PROJECT_TOKEN
1323
+ cloud:
1324
+ url: https://hub.kxmd.dev
1325
+ project: prj_example
1326
+ key:
1327
+ op: op://Private/kxmd/project-token
1328
+ env: KXMD_HUB_TOKEN
1329
+ projects:
1330
+ prj_example:
1331
+ op: op://Private/kxm/local-project-token
1332
+ env: KXM_LOCAL_PROJECT_TOKEN
1308
1333
  improvement:
1309
1334
  promotionPolicy: manual_pr # manual_pr | critic_quorum | auto_threshold (readiness only)
1310
1335
  telemetryHalfLifeDays: 14
@@ -108,7 +108,7 @@ Every agent client (the Pi extension, the Claude Code MCP server, and the `kxm p
108
108
  |---|---|---|
109
109
  | `KXM_SERVER_URL` | `http://127.0.0.1:7331` | Hub base URL. For the CLI, the machine's `kxm hub bind` URL is used when this is unset |
110
110
  | `KXM_AUTH_TOKEN` | See below | The project token for this agent's project |
111
- | `KXM_PROJECT` | `id` in the nearest `.kxm/project.yaml`, else `name` in `package.json` in the working directory, else the directory name | Project for discovery and authentication. An explicit `--project` flag on `kxm peer list` and `kxm tenant status` wins over this variable. The same resolver is used by peer commands, tenant status, workers, the Pi extension, and the Claude Code MCP server |
111
+ | `KXM_PROJECT` | Active mode's `project` in `.kxm/config.yaml`, else `id` in the nearest `.kxm/project.yaml`, else `name` in `package.json` in the working directory, else the directory name | Project for discovery and authentication. An explicit `--project` flag wins over this variable, and this variable wins over the config file. The same resolver is used by peer commands, tenant status, workers, the Pi extension, dash, and the Claude Code MCP server |
112
112
  | `KXM_AGENT_NAME` | Harness-specific (see below) | Name peers see; unique among online agents in the project, compared case-insensitively |
113
113
  | `KXM_AGENT_PURPOSE` | Harness-specific (see below) | One line peers use to decide what to send this agent |
114
114
 
@@ -120,7 +120,7 @@ Every agent client (the Pi extension, the Claude Code MCP server, and the `kxm p
120
120
 
121
121
  A clean shutdown marks an identity offline. Reconnecting with the same project and name resumes its durable agent ID and rotates its agent key. If the Claude Code name is already online in the project, the MCP server registers once more as `<name>-<pid>`.
122
122
 
123
- A `--cloud` hub binding replaces this table's token lookup for every client, including agents. The token comes from the binding's `--token-env` or `--token-command`, never from this machine's hub-env file, and it is not written to disk. `kxm agent worker` copies it into the child process environment as `KXM_AUTH_TOKEN`.
123
+ A cloud hub mode replaces this table's token lookup for every client, including agents. The token comes from that mode's key reference in `.kxm/config.yaml` (`key.env`, then `key.op` via `op read`), then from the binding's `--token-env` or `--token-command`. It never comes from this machine's hub-env file, and it is not written to disk. `kxm agent worker` copies it into the child process environment as `KXM_AUTH_TOKEN`. Local mode uses `KXM_AUTH_TOKEN`, then the local key reference, then the saved project token, and still never the admin token.
124
124
 
125
125
  Also check plugin.json is valid JSON.
126
126
 
@@ -64,7 +64,7 @@ Every tool returns its result as JSON text; Pi also attaches the same value as s
64
64
 
65
65
  | Error text | Harness | Fix |
66
66
  |---|---|---|
67
- | `KXM has no project token for project <p> on this machine` | Claude Code | Set `auth_token` with `/plugin configure kxm@kxm`, or [give the project a token](../start/quickstart-claude-code.md#give-the-project-a-token-on-the-running-hub) on the hub |
67
+ | `kxm has no project token for project <p>` | Claude Code and the Pi extension | The message names where `<p>` came from. Set `hub.local.project` or `hub.cloud.project` and a key reference in `.kxm/config.yaml`, set `auth_token` with `/plugin configure kxm@kxm`, or [give the project a token](../start/quickstart-claude-code.md#give-the-project-a-token-on-the-running-hub) on the hub |
68
68
  | `KXM hub unreachable at <url> (<cause>)` | Claude Code | Start the hub with `kxm hub start`, or correct `server_url` |
69
69
  | `KXM hub rejected the project token for project <p>` | Claude Code | Enter that project's token from the hub's `KXM_PROJECT_TOKENS` |
70
70
  | `kxm hub is not connected; check KXM_SERVER_URL and /kxm hub` | Pi | Start the hub or fix `KXM_SERVER_URL`, then restart the session |
@@ -181,7 +181,7 @@ Claude Code asks for these options at install. Change them later with `/plugin c
181
181
  | `auth_token` | Blank | Blank on the machine that runs the hub. Elsewhere, this project's token. Never the admin token. |
182
182
  | `agent_name` | `claude` | The name peers see. A second concurrent session in the project registers as `<name>-<pid>`. |
183
183
  | `agent_purpose` | `Claude Code implementation and review agent` | One line that peers use to decide what to send this agent |
184
- | `project` | Blank | `<hub-project>`. Blank uses the `name` in `package.json`, then the directory name. |
184
+ | `project` | Blank | `<hub-project>`. Blank uses `hub.local.project` or `hub.cloud.project` in `.kxm/config.yaml` for the active mode, then the `id` in `.kxm/project.yaml`, then the `name` in `package.json`, then the directory name. |
185
185
 
186
186
  With a blank `auth_token`, the plugin uses the project token the hub saved for `project` in `hub-env.json`, and only that token. It never uses the admin token. On another machine, get the project token from whoever runs the hub, through a password manager, and enter it at `/plugin configure kxm@kxm`. [Plugin settings](../reference/config-reference.md#claude-code-plugin-settings) has the full rules.
187
187
 
@@ -394,7 +394,7 @@ The `kxm_*` tools and the session brief name the fix for setup problems. Run the
394
394
  | Message or symptom | Cause | Fix |
395
395
  |---|---|---|
396
396
  | `KXM hub unreachable at <url>` | No hub answers at `server_url` | Start the hub with `kxm hub start`, or correct `server_url` and restart Claude Code |
397
- | `KXM has no project token for project <p> on this machine` | No `auth_token`, and the hub saved no token for `<p>` | Add `<p>` with [step 3](#3-start-the-hub), enter its token, or fix the `project` option |
397
+ | `kxm has no project token for project <p>` | No `auth_token`, and the hub saved no token for `<p>`. The message names where `<p>` came from | Set `hub.<mode>.project` in `.kxm/config.yaml` to the key the hub knows, add a key reference, or add `<p>` with [step 3](#3-start-the-hub). Never paste the token into the file |
398
398
  | `KXM hub rejected the project token for project <p>` | `auth_token` is not the hub's token for `<p>` | Enter the right token at `/plugin configure kxm@kxm` |
399
399
  | `tool_policy_denied: Session token on disk is malformed or expired` | A stale session token file blocks every tool | Run `kxm session token --clear`; it prints `Session token cleared from disk.` |
400
400
  | `tool_policy_denied: KXM_SESSION_TOKEN is malformed or expired` | A bad `KXM_SESSION_TOKEN` in Claude Code's environment | Unset or replace it where you launch Claude Code, then restart it |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextmind/kxm",
3
- "version": "0.7.165",
3
+ "version": "0.7.167",
4
4
  "description": "KXM local-first multi-agent orchestration and operator dashboard",
5
5
  "type": "module",
6
6
  "author": "KontextMind",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "kxm",
4
4
  "displayName": "KXM",
5
- "version": "0.7.165",
5
+ "version": "0.7.167",
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",
@@ -58,7 +58,7 @@ Claude Code asks for these options when you install the plugin. Change them late
58
58
  | `auth_token` | `KXM_AUTH_TOKEN` | Blank | This project's token from the hub's `KXM_PROJECT_TOKENS`. Leave it blank on the machine that runs the hub. Never the hub admin token. Marked sensitive. |
59
59
  | `agent_name` | `KXM_AGENT_NAME` | `claude` | Name other agents see. The first active session in a project keeps it; a later concurrent session registers as `<name>-<pid>`. |
60
60
  | `agent_purpose` | `KXM_AGENT_PURPOSE` | `Claude Code implementation and review agent` | One line that peers use to decide what to send this agent. |
61
- | `project` | `KXM_PROJECT` | Blank | Hub project key; must match a key in the hub's `KXM_PROJECT_TOKENS`. Blank uses the `id` in `.kxm/project.yaml`, then `name` from `package.json`, then the directory name. |
61
+ | `project` | `KXM_PROJECT` | Blank | Hub project key. Blank uses the active mode's `project` in `.kxm/config.yaml`, then the `id` in `.kxm/project.yaml`, then `name` from `package.json`, then the directory name. |
62
62
 
63
63
  The MCP server also receives `KXM_PROJECT_DIR`, set to the directory Claude Code was started in (`CLAUDE_PROJECT_DIR`). It decides the default project key and whether this is a KXM project (one with a `.kxm/` directory).
64
64
 
@@ -69,7 +69,7 @@ The plugin acts as an agent of one hub project and authenticates with that proje
69
69
  - On the machine that runs the hub, leave `auth_token` blank. The MCP server then uses the project token the hub saved for this project in `hub-env.json` under the user state root (`KXM_STATE_HOME`, or the platform default listed in [State outside the project](../../docs/reference/config-reference.md#state-outside-the-project)). It uses only that entry, never the admin token saved beside it.
70
70
  - On any other machine, enter this project's token at `/plugin configure kxm@kxm`. Get it from whoever runs the hub, through your password manager. When the machine is bound with `kxm hub bind --cloud`, leave `auth_token` blank: the MCP server reads the binding's token source and does not store the token. The recipe is [Cross-box peer attach](../../docs/operations.md#cross-box-peer-attach).
71
71
  - Never enter the hub admin token. It is the operator's credential. The hub accepts it for any project that has no token of its own, so an agent holding it could act in projects it was never given.
72
- - Without a project token, every `kxm_*` tool fails with `KXM has no project token for project <p> on this machine`, and the MCP server does not contact the hub.
72
+ - Without a project token, every `kxm_*` tool fails with `kxm has no project token for project <p>`, naming where that id came from, and the MCP server does not contact the hub.
73
73
 
74
74
  To give a project a token, the operator adds it to `KXM_PROJECT_TOKENS` and restarts the hub. That variable replaces the hub's saved token map rather than merging with it, so it must list every project, existing and new. [Add Claude Code to an existing project](../../docs/start/quickstart-claude-code.md#add-claude-code-to-an-existing-project) has a command that builds the full map. Run it in your own terminal, and never paste tokens or `hub-env.json` into Claude.
75
75
 
@@ -210,7 +210,7 @@ No hub answers at `server_url`. Start it with `kxm hub start`, or correct `serve
210
210
 
211
211
  ### `no project token for project <p>`
212
212
 
213
- The MCP server found neither an `auth_token` nor a token the hub saved for `<p>`, so it did not contact the hub. Enter the project's token at `/plugin configure kxm@kxm`, or add `<p>` to the hub's `KXM_PROJECT_TOKENS`, listing every existing project too because the variable replaces the saved map, and restart the hub. If `<p>` is not the key you expected, set the `project` option.
213
+ The MCP server found neither an `auth_token` nor a token the hub saved for `<p>`, so it did not contact the hub. The message names where `<p>` came from. Enter the project's token at `/plugin configure kxm@kxm`, set `hub.local.project` or `hub.cloud.project` in `.kxm/config.yaml` to the key the hub already knows, or add `<p>` to the hub's `KXM_PROJECT_TOKENS` or `hub.projects` map. `KXM_PROJECT_TOKENS` replaces the saved map, so list every existing project, then restart the hub. Never paste the token into the config file.
214
214
 
215
215
  ### `KXM hub rejected the project token for project <p>`
216
216