@kontextmind/kxm 0.7.102 → 0.7.104

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,7 +11,7 @@
11
11
  "name": "kxm",
12
12
  "source": "./plugins/kxm",
13
13
  "description": "Durable workflows, peer agents, and kxm tui",
14
- "version": "0.7.102",
14
+ "version": "0.7.104",
15
15
  "category": "development",
16
16
  "tags": ["kxm", "multi-agent", "workflows", "mcp"]
17
17
  }
package/CHANGELOG.md CHANGED
@@ -70,7 +70,9 @@ All notable user-facing changes are documented here. The project follows [Semant
70
70
  ### Changed
71
71
 
72
72
  - **The rotation surface drive uses is the one setup writes.** Guide setup appends only
73
- reviewed selectors to `.kxm/routes.yaml` and routes Google through Pi `antigravity`.
73
+ reviewed selectors to `.kxm/routes.yaml`. It skips Google guide candidates: Google's
74
+ route is the Pi `antigravity` provider, which a Runtime drive cannot reach yet, so a
75
+ Google role falls to its next reviewed candidate or is not written.
74
76
 
75
77
  - **CLI and Studio stop reporting work they did not do.** Drive help no longer
76
78
  describes the default as a model-free simulation. A Studio mutation with no handler returns 501 and `mappedToCli: false`.
@@ -347,14 +349,33 @@ All notable user-facing changes are documented here. The project follows [Semant
347
349
  and admits those two routes. One-shot production no longer falls through to an
348
350
  unadmitted `claude-3-7-sonnet`.
349
351
 
350
- - **`kxm backup` includes the Runtime stores under the user-state root.** Discovery
351
- copies `$S/runtime/registry.db` and `$S/runtime/projects/<projectKey>/run-events.db`,
352
- plus each `run-events.db.run-prompts.json` sidecar. A copy that misses a discovered
353
- store is `complete: false`: `kxm backup` exits 1 with `ok: false`, and restore
354
- refuses that manifest. Cross-box remap of absolute `$S` paths is still the file recipe.
355
- The Runtime stores are machine-wide, so a backup holds every project's run store and a
356
- restore rolls all of them back. `kxm backup --help` no longer says Runtime stores are
357
- left out.
352
+ - **`kxm backup` includes this project's Runtime event store, and never another
353
+ project's unless asked.** Discovery copies the checkout's own
354
+ `$S/runtime/projects/<projectKey>/run-events.db`, with the key derived from the
355
+ canonical checkout path as the Runtime derives it, plus its
356
+ `run-events.db.run-prompts.json` sidecar. `kxm backup` and `kxm restore` act for the
357
+ checkout the Runtime would use (the Git root holding `.kxm/project.yaml`), so running
358
+ them from a subdirectory finds the same stores. The shared `$S/runtime/registry.db` and
359
+ every other project's event store are copied only with `kxm backup --all-projects`, and
360
+ a restore of a backup that holds them is refused with `restore_requires_all_projects`
361
+ unless `kxm restore --all-projects` is given; a project restore therefore never rolls
362
+ back another project's runs, receipts or sync outbox, or the registry. A project
363
+ restore writes the event store where the Runtime looks for the checkout being
364
+ restored, under the current `KXM_STATE_HOME`; `--all-projects` rebases the shared
365
+ stores onto the current user state root. The manifest records `scope`, `stateRoot`
366
+ and `runtimeProjectKey`. A copy that misses a discovered store is `complete: false`:
367
+ `kxm backup` exits 1 with `ok: false`, and restore refuses that manifest.
368
+ `kxm backup --help` no longer says Runtime stores are left out.
369
+
370
+ - **`kxm restore` refuses while the Runtime supervisor or a hub is running.** Before any
371
+ write, and under `--dry-run` too, it fails with `restore_runtime_running` when the
372
+ supervisor is live by the same test `kxm runtime status` uses (running state, fresh
373
+ heartbeat, live PID), read through a read-only open of the registry, and with
374
+ `restore_hub_running` when a live `hub.pid` claim sits beside a hub store it would
375
+ overwrite. A registry too broken to read fails closed with
376
+ `restore_runtime_unverified`, which says to stop the Runtime and move the registry
377
+ aside. Replacing a SQLite file under an open writer could lose commits or corrupt the
378
+ store.
358
379
 
359
380
  - **Signed webhooks cannot be replayed.** KXM's own webhook senders now sign the
360
381
  timestamp, delivery ID, definition, run and signal key along with the body
@@ -169,7 +169,7 @@ Every store opens in WAL mode with a 5-second busy timeout, `synchronous=NORMAL`
169
169
  ## Reset a store
170
170
 
171
171
  > [!CAUTION]
172
- > Deleting a store erases its history for good. Back it up first if you might need it. `kxm backup` copies the hub store and the Runtime stores in the user state root, for every project on the machine.
172
+ > Deleting a store erases its history for good. Back it up first if you might need it. `kxm backup` copies the hub store and this project's Runtime event store; `kxm backup --all-projects` adds the Runtime registry and every project's event store.
173
173
 
174
174
  Stop every writer first, then delete each database together with its sidecars:
175
175
 
@@ -136,17 +136,19 @@ The context suites in detail:
136
136
  | Metadata-only dashboard: ops mode, presence-only fallback, observer filtering, keys, body-free local projection | `tui.test.ts`, `hub-api.test.ts` |
137
137
  | Restricted loader, deterministic bundle hash, init classification, atomic creation, three-way repair, crash resumption | `project-config.test.ts`, `cli.test.ts`, `package-install.test.ts` |
138
138
  | Legacy `.kxm/config` JSON is refused with `legacy_state_unsupported`; `kxm migrate` is unknown; older stores are refused | `project-config.test.ts`, `cli.test.ts`, `e6-backup-restore-migrations.test.ts` |
139
- | `kxm backup` and `kxm restore` round-trip the hub store and Runtime stores seeded under `.kxm/runtime/`; Runtime stores and prompt sidecars under `KXM_STATE_HOME` are discovered; tampered, newer or incomplete (`complete: false`) backups are refused | `e6-backup-restore-migrations.test.ts` |
139
+ | `kxm backup` and `kxm restore` round-trip the hub store and Runtime stores seeded under `.kxm/runtime/`; a project backup under `KXM_STATE_HOME` holds only its own event store and sidecar, and its restore leaves another project and the registry alone; `--all-projects` holds and restores every project and the registry, and restore refuses it without the flag; restore refuses while the supervisor or a hub is live, `--dry-run` included; tampered, newer or incomplete (`complete: false`) backups are refused | `e6-backup-restore-migrations.test.ts` |
140
140
  | Permission-diff trust: authority lattice, prose neutrality, Git base shadowing, CLI diff and check | `permission.test.ts`, `cli.test.ts`, `contracts.test.ts`, `package-install.test.ts` |
141
141
  | KXM schemas, restricted YAML fixtures, cross-resource semantics and sync-safe rejection | `contracts.test.ts`, `restricted-yaml.test.ts` |
142
142
  | Harness detection, auth and dispatch for the built-in catalog, including Windows launch rules | `harness.test.ts` |
143
143
  | `kxm update`: `update.yaml` validation, GitHub or npm version checks, install-kind detection, `kxm-<v>.tgz` asset selection | `kxm-update.test.ts`, `kxm-update-cli.test.ts`, `kxm-install-kind.test.ts` |
144
144
 
145
145
  The round trip seeds its Runtime stores in a project-local `.kxm/runtime/`
146
- layout that the Runtime never writes. A separate test seeds a registry, an event
147
- store and its prompt sidecar under a temporary `KXM_STATE_HOME` and checks that
148
- `kxm backup` finds them and that a partial manifest is refused. No test backs up
149
- stores a running supervisor wrote.
146
+ layout that the Runtime never writes. Separate tests seed two projects' event
147
+ stores, their prompt sidecars and a shared registry under a temporary
148
+ `KXM_STATE_HOME`, at the paths the Runtime derives, and check each scope and
149
+ that a partial manifest is refused. The supervisor-liveness test fakes a live
150
+ supervisor with a fresh registry record naming the test's own PID; no test backs
151
+ up or restores stores a running supervisor wrote.
150
152
 
151
153
  ## Packaging, release and repository gates
152
154
 
@@ -59,17 +59,16 @@ Record every override with the backup. A restore that lands where the running se
59
59
 
60
60
  ## Know what each backup covers
61
61
 
62
- `kxm backup` copies the SQLite stores it can find: the hub store under the current directory, and the Runtime stores and their prompt sidecars under the user state root. Everything else needs the stopped-state copy described below.
62
+ `kxm backup` copies the SQLite stores that belong to the checkout it runs in: the hub store under the checkout, and the checkout's own Runtime event store and its prompt sidecar under the user state root. It finds that event store the way the Runtime does, by a key derived from the canonical checkout path. Everything else needs `--all-projects` or the stopped-state copy described below.
63
63
 
64
- > [!WARNING]
65
- > The Runtime stores are shared by every project on the machine. `kxm backup` copies `$S/runtime/registry.db` and the `run-events.db` of every project under `$S/runtime/projects/`, not only the project you run it from, and `kxm restore` writes all of them back. Restoring one project's backup returns every project's runs to the moment of that backup.
64
+ The Runtime registry and the other projects' event stores are shared by every project on the machine, so a project backup leaves them out, and a project restore never rolls them back. The registry holds the supervisor's identity and each project's registration, including the home Runtime id that every one of that project's runs records. A project restore relies on the registry that is already on the machine. `kxm backup --all-projects` adds the registry and every project's event store for a whole-machine copy, and only `kxm restore --all-projects` restores one.
66
65
 
67
66
  | Path | Holds | In `kxm backup` |
68
67
  |---|---|---|
69
- | `$W/kxm.db` | Hub store: agents, messages, workflow runs, journals, context items, leases, synced run facts | Yes, at `<current directory>/.kxm/state/kxm.db` only |
70
- | `$S/runtime/registry.db` | Runtime registry: projects, their roots, the supervisor identity and claim | Yes (`registry`) |
71
- | `$S/runtime/projects/<key>/run-events.db` | Event-sourced runs, drive receipts, gate evidence, the sync outbox | Yes, for every project (`events:<key>`) |
72
- | `$S/runtime/projects/<key>/run-events.db.run-prompts.json` | Run prompt text; restoring a store without it loses every prompt | Yes, as a plain file (`events:<key>:run-prompts`) |
68
+ | `$W/kxm.db` | Hub store: agents, messages, workflow runs, journals, context items, leases, synced run facts | Yes, at `<checkout>/.kxm/state/kxm.db` only |
69
+ | `$S/runtime/projects/<key>/run-events.db` | Event-sourced runs, drive receipts, gate evidence, the sync outbox | This checkout's (`events:<key>`); every project's with `--all-projects` |
70
+ | `$S/runtime/projects/<key>/run-events.db.run-prompts.json` | Run prompt text; restoring a store without it loses every prompt | With its event store, as a plain file (`events:<key>:run-prompts`) |
71
+ | `$S/runtime/registry.db` | Runtime registry: projects, their roots and home Runtime, the supervisor identity and claim | Only with `--all-projects` (`registry`) |
73
72
  | `$S/projects/<hash>/repository-bindings.json`, `$S/update.yaml` | Member repository paths; updater settings | No |
74
73
  | `$S/hub-env.json`, `$S/hub-binding.json`, `$C/session.token` | Credentials and the machine's hub binding | No; prefer regenerating secrets to copying them |
75
74
  | `$R/.kxm/` definition files and durable records | Project, roles, routes, prices, roster, memory, skills, goals, tasks, candidates | No; commit them to Git or copy the checkout |
@@ -84,7 +83,7 @@ These files are disposable and need no backup: `hub.pid`, `hub.stop`, `worker-*.
84
83
 
85
84
  ## Back up the SQLite stores with `kxm backup`
86
85
 
87
- Run it from the checkout root. It finds the hub store from the current directory and ignores `--workspace`, `KXM_WORKDIR`, `KXM_STATE_DIR` and `KXM_DATA_PATH`, so a relocated hub database is not found. It finds the Runtime stores under the user state root, including one moved with `KXM_STATE_HOME`.
86
+ Run it inside the checkout. It acts for the checkout the Runtime would use: the Git root that holds `.kxm/project.yaml`, or the current directory outside one. It finds the hub store under that checkout and ignores `--workspace`, `KXM_WORKDIR`, `KXM_STATE_DIR` and `KXM_DATA_PATH`, so a relocated hub database is not found. It finds the checkout's event store under the user state root, including one moved with `KXM_STATE_HOME`.
88
87
 
89
88
  Preview first. A dry run lists what it would write, opens no store and writes nothing:
90
89
 
@@ -96,9 +95,8 @@ kxm backup --dry-run
96
95
  Expected output:
97
96
 
98
97
  ```text
99
- dry run: back up 3 store(s) and 1 file(s) to /srv/kxm/product/.kxm/backups/backup-2026-09-23T18-29-09-107Z (sources are not opened, so their WAL is not checkpointed)
98
+ dry run: back up 2 store(s) and 1 file(s) (project scope) to /srv/kxm/product/.kxm/backups/backup-2026-09-23T18-29-09-107Z (sources are not opened, so their WAL is not checkpointed)
100
99
  would write /srv/kxm/product/.kxm/backups/backup-2026-09-23T18-29-09-107Z/kxm.db
101
- would write /srv/kxm/product/.kxm/backups/backup-2026-09-23T18-29-09-107Z/registry.db
102
100
  would write /srv/kxm/product/.kxm/backups/backup-2026-09-23T18-29-09-107Z/run-events.db
103
101
  would write /srv/kxm/product/.kxm/backups/backup-2026-09-23T18-29-09-107Z/run-events.db.run-prompts.json
104
102
  would write /srv/kxm/product/.kxm/backups/backup-2026-09-23T18-29-09-107Z/manifest.json
@@ -113,14 +111,13 @@ kxm backup --out /backups/kxm/2026-09-23/sqlite
113
111
  Expected output:
114
112
 
115
113
  ```text
116
- Created SQLite backup with 3 store(s):
114
+ Created SQLite backup with 2 store(s) (project scope):
117
115
  - hub-store: /srv/kxm/product/.kxm/state/kxm.db -> kxm.db (schema v5, 110592 bytes, sha256 sha256:86549...)
118
- - registry: /home/kxm/.local/state/kxm/runtime/registry.db -> registry.db (schema v1, 20480 bytes, sha256 sha256:a5bde...)
119
116
  - events:38ed26cb8eeaa297f3b0b452: /home/kxm/.local/state/kxm/runtime/projects/38ed26cb8eeaa297f3b0b452/run-events.db -> run-events.db (schema v7, 348160 bytes, sha256 sha256:27c13...)
120
117
  Manifest: /backups/kxm/2026-09-23/sqlite/manifest.json
121
118
  ```
122
119
 
123
- The summary lists stores only; the prompt sidecar is in the manifest's `files`. When two projects' event stores share a file name, the second copy is prefixed with its store id.
120
+ The summary lists stores only; the prompt sidecar is in the manifest's `files`. The manifest also records its `scope` (`project` or `all-projects`), the user state root it copied from (`stateRoot`), and this checkout's store key (`runtimeProjectKey`).
124
121
 
125
122
  For each store, `kxm backup` checkpoints the write-ahead log, runs `PRAGMA integrity_check`, copies the database with `VACUUM INTO`, checks the copy's integrity, sets mode `0600`, and records its schema version and SHA-256 in `manifest.json` (`kxm.backup-manifest.v1`). `VACUUM INTO` reads one consistent snapshot, so the hub and the Runtime can keep running during this step. Each prompt sidecar is copied as a regular file with mode `0600` and its SHA-256 recorded.
126
123
 
@@ -129,7 +126,17 @@ A backup is complete only when it copied everything it found. If a store or side
129
126
  > [!NOTE]
130
127
  > Without `--out`, backups go to `.kxm/backups/` inside the checkout. Keep that directory out of Git, or always pass `--out`.
131
128
 
132
- It fails with `backup_no_stores` when it finds no store at all, neither `.kxm/state/kxm.db` under the current directory nor a Runtime store under the user state root, and with `database_corrupted` when an integrity check fails.
129
+ It fails with `backup_no_stores` when it finds no store at all, neither `.kxm/state/kxm.db` under the checkout nor the checkout's event store under the user state root, and with `database_corrupted` when an integrity check fails.
130
+
131
+ ### Back up every project on the machine
132
+
133
+ `--all-projects` adds the Runtime registry and the event store and prompt sidecar of every project under `$S/runtime/projects/`:
134
+
135
+ ```bash
136
+ kxm backup --all-projects --out /backups/kxm/2026-09-23/sqlite
137
+ ```
138
+
139
+ Use it for a whole-machine copy, together with the stopped-state copy below. When two projects' event stores share a file name, the second copy is prefixed with its store id. Restoring this backup takes `kxm restore --all-projects` and rolls back every project on the machine.
133
140
 
134
141
  ## Back up everything else
135
142
 
@@ -151,11 +158,11 @@ Copy the remaining state with both services stopped. SQLite runs in write-ahead-
151
158
  S="${KXM_STATE_HOME:-$HOME/.local/state/kxm}" # macOS: "$HOME/Library/Application Support/KXM"
152
159
  B=/backups/kxm/2026-09-23
153
160
  mkdir -p "$B"
154
- kxm backup --out "$B/sqlite"
161
+ kxm backup --all-projects --out "$B/sqlite"
155
162
  tar -C "$S" --exclude 'supervisor.token' --exclude 'hub-env.json' -czf "$B/user-state.tgz" .
156
163
  ```
157
164
 
158
- `kxm backup` already holds the Runtime stores and sidecars. The archive holds them again, as files, together with what `kxm backup` does not copy: the repository bindings, the hub binding and `update.yaml`. It leaves out the credential file; keep tokens in your secret store, or include `hub-env.json` and protect the archive as a secret.
165
+ `kxm backup --all-projects` already holds the registry and every project's event store and sidecar. The archive holds them again, as files, together with what `kxm backup` does not copy: the repository bindings, the hub binding and `update.yaml`. It leaves out the credential file; keep tokens in your secret store, or include `hub-env.json` and protect the archive as a secret.
159
166
 
160
167
  If `KXM_STATE_DIR` or `KXM_DATA_PATH` moved the hub database, `kxm backup` fails with `backup_no_stores`. With both services stopped, copy that database file and any `-wal` and `-shm` files instead.
161
168
  4. Copy the other roots your recovery needs: the checkout's untracked `.kxm/` records, `$D/assets/`, `$W/worker-*.json` (and `$W/pi-sessions/` only if your policy keeps model history), and `$C`.
@@ -166,9 +173,15 @@ Keep at least one previous backup, and bound retention: run events and prompt si
166
173
 
167
174
  ## Restore with `kxm restore`
168
175
 
169
- `kxm restore` overwrites every live database in the manifest, including the Runtime stores of every project on the machine, and deletes their `-wal` and `-shm` files. It does not check whether the hub or the Runtime is running. Stop the hub and the Runtime first, and move the current state aside rather than deleting it.
176
+ `kxm restore` overwrites the live databases it restores and deletes their `-wal` and `-shm` files. Before it writes anything, it refuses:
177
+
178
+ - While the Runtime supervisor is running (`restore_runtime_running`), judged as `kxm runtime status` judges it. The supervisor holds the registry and every project's event store open.
179
+ - While a hub holds the hub store it would overwrite (`restore_hub_running`), seen as a live `hub.pid` claim in that store's directory.
180
+ - A backup that holds the registry or another project's event store (`restore_requires_all_projects`), unless you pass `--all-projects`.
181
+
182
+ Stop the hub and the Runtime first and keep them stopped, as in the backup procedure. Move the current state aside rather than deleting it.
170
183
 
171
- Preview the restore. The dry run performs every check below and lists what it would overwrite:
184
+ Preview the restore. The dry run performs every check on this page, including the supervisor and hub checks, and lists what it would overwrite:
172
185
 
173
186
  ```bash
174
187
  cd /srv/kxm/product
@@ -178,11 +191,10 @@ kxm restore /backups/kxm/2026-09-23/sqlite/manifest.json --dry-run
178
191
  Expected output:
179
192
 
180
193
  ```text
181
- dry run: restore 3 store(s) and 1 file(s) from /backups/kxm/2026-09-23/sqlite/manifest.json; digests verified against the manifest
194
+ dry run: restore 2 store(s) and 1 file(s) from /backups/kxm/2026-09-23/sqlite/manifest.json; digests verified against the manifest
182
195
  would write /srv/kxm/product/.kxm/state/kxm.db
183
196
  would delete /srv/kxm/product/.kxm/state/kxm.db-wal
184
197
  would delete /srv/kxm/product/.kxm/state/kxm.db-shm
185
- would write /home/kxm/.local/state/kxm/runtime/registry.db
186
198
  would write /home/kxm/.local/state/kxm/runtime/projects/38ed26cb8eeaa297f3b0b452/run-events.db
187
199
  would write /home/kxm/.local/state/kxm/runtime/projects/38ed26cb8eeaa297f3b0b452/run-events.db.run-prompts.json
188
200
  ```
@@ -196,15 +208,32 @@ kxm restore /backups/kxm/2026-09-23/sqlite/manifest.json
196
208
  Expected output:
197
209
 
198
210
  ```text
199
- Restored 3 SQLite store(s) from /backups/kxm/2026-09-23/sqlite/manifest.json:
211
+ Restored 2 SQLite store(s) from /backups/kxm/2026-09-23/sqlite/manifest.json:
200
212
  - hub-store: -> /srv/kxm/product/.kxm/state/kxm.db (schema v5, integrity ok)
201
- - registry: -> /home/kxm/.local/state/kxm/runtime/registry.db (schema v1, integrity ok)
202
213
  - events:38ed26cb8eeaa297f3b0b452: -> /home/kxm/.local/state/kxm/runtime/projects/38ed26cb8eeaa297f3b0b452/run-events.db (schema v7, integrity ok)
203
214
  ```
204
215
 
205
216
  Before it overwrites anything, `kxm restore` checks that the manifest is a `kxm.backup-manifest.v1` document that does not record `complete: false` (`restore_incomplete`), that every listed file exists, that each file's SHA-256 matches the manifest, and that no store is newer than this build supports. The manifest's own `manifestSha256` is not checked. A manifest from an older build that has no `complete` field still restores.
206
217
 
207
- It then checks each backup's integrity and schema version again, copies it into place with mode `0600`, checks the result, and then copies the prompt sidecars back. A store under the checkout is rebased onto the current directory when the manifest came from another checkout. The Runtime stores and sidecars return to their recorded absolute paths under the user state root; restore does not move them to a different machine's or a different `KXM_STATE_HOME`.
218
+ It then checks each backup's integrity and schema version again, copies it into place with mode `0600`, checks the result, and then copies the prompt sidecars back. Each target is worked out from the checkout you restore into:
219
+
220
+ - A store under the manifest's project root is rebased onto this checkout.
221
+ - The backed-up checkout's own event store and its sidecar go to the store the Runtime derives for this checkout, under the current user state root. A restore under a moved `KXM_STATE_HOME` lands where the Runtime looks.
222
+ - With `--all-projects`, the registry and every other event store are rebased from the manifest's `stateRoot` onto the current user state root.
223
+ - A manifest written before backups were scoped has no `stateRoot`. Its Runtime stores are bare absolute paths, count as machine-wide, and restore only with `--all-projects`, to those paths.
224
+
225
+ A project restore leaves the registry alone. The restored runs record the home Runtime id that the registry already holds for this project, so the Runtime keeps owning them. If the registry itself was lost, a project restore cannot bring it back: restore an `--all-projects` backup or the archive.
226
+
227
+ ### Restore every project
228
+
229
+ Restore a backup taken with `--all-projects` only when rolling every project back to the backup's moment is what you want:
230
+
231
+ ```bash
232
+ kxm restore /backups/kxm/2026-09-23/sqlite/manifest.json --all-projects --dry-run
233
+ kxm restore /backups/kxm/2026-09-23/sqlite/manifest.json --all-projects
234
+ ```
235
+
236
+ It restores the registry and every project's event store and sidecar. Every checkout must still be at the absolute path the registry records.
208
237
 
209
238
  ### Restore ceilings
210
239
 
@@ -221,7 +250,7 @@ The ceilings come from `KXM_BACKUP_CEILINGS` in `plugins/kxm/src/database.ts` an
221
250
 
222
251
  ### Restore the Runtime stores by hand
223
252
 
224
- `kxm restore` puts the Runtime stores back at the paths they came from. Use the archive instead when the user state root moved, or when you also need the bindings and `update.yaml`.
253
+ Use the archive instead of `kxm restore` when you also need the bindings and `update.yaml`, or when a backup holds only the SQLite copies you no longer trust.
225
254
 
226
255
  1. Stop the Runtime and the hub, as in the backup procedure.
227
256
  2. Move `$S/runtime/registry.db` and `$S/runtime/projects/` aside.
@@ -248,11 +277,14 @@ Test a full restore on a spare machine before you rely on it, and repeat the tes
248
277
 
249
278
  | Symptom | Cause | Fix |
250
279
  |---|---|---|
251
- | `backup_no_stores` | No `.kxm/state/kxm.db` under the current directory (or it was moved with `KXM_STATE_DIR` or `KXM_DATA_PATH`) and no Runtime store under the user state root | Run from the checkout root; copy a relocated database with the stopped-state procedure |
280
+ | `backup_no_stores` | No `.kxm/state/kxm.db` under the checkout (or it was moved with `KXM_STATE_DIR` or `KXM_DATA_PATH`) and no event store for this checkout under the user state root | Run inside the checkout; copy a relocated database with the stopped-state procedure |
252
281
  | `Backup is incomplete (<n> omitted); not ok:`, exit 1 | A store or sidecar could not be copied, or appeared while the backup ran | Fix the source named after `omitted`, then run `kxm backup` again |
253
282
  | `restore_incomplete` | The manifest records `complete: false` | Restore a complete backup; the partial one is not restorable |
254
- | Runs are missing after a restore | The checkout moved to another absolute path, so the Runtime derives a different store key, or the user state root changed | Keep the checkout at its original path and restore under the same `KXM_STATE_HOME` |
255
- | Another project's recent runs disappeared after a restore | `kxm restore` rolled back every project's Runtime store to the backup's moment | Restore that project's store from a newer backup or from the moved-aside copy |
283
+ | Runs are missing, or the Runtime refuses the project with `project_home_conflict`, after a restore | The checkout moved to another absolute path, and the registry still binds the project to the old one | Keep the checkout at its original path and restore there |
284
+ | `restore_requires_all_projects` | The backup holds the Runtime registry or another project's event store: it was taken with `--all-projects`, or by a build from before backups were scoped | Pass `--all-projects` if rolling back every project is what you want; otherwise restore a backup taken without it |
285
+ | `restore_runtime_running` | The Runtime supervisor is running | Run `kxm runtime stop`, pause whatever restarts it, then restore |
286
+ | `restore_runtime_unverified` | `$S/runtime/registry.db` cannot be read, so restore cannot tell whether the supervisor is running | Stop the Runtime, move the registry aside, then restore; an `--all-projects` backup brings the registry back |
287
+ | `restore_hub_running` | A live `hub.pid` claim sits beside the hub store the restore would overwrite | Run `kxm hub stop`, then restore. If no hub is running and the claim's PID now belongs to another process, delete the stale `hub.pid`; it is disposable |
256
288
  | `restore_manifest_digest_mismatch` | A backup file changed after the manifest was written | Use another backup; do not edit files in a backup set |
257
289
  | `restore_file_missing` | A file listed in the manifest is not beside it | Copy the whole backup directory, not only `manifest.json` |
258
290
  | `runtime_schema_mismatch` | A backup file's schema version differs from the one its manifest records | Use another backup set; never mix files between sets |
@@ -237,7 +237,7 @@ flowchart LR
237
237
  Hold these invariants on every tenant box:
238
238
 
239
239
  1. **A service account, not root.** Session isolation routes model context; it is not a sandbox against a hostile process under the same account. Give untrusted workers separate accounts or containers.
240
- 2. **Explicit, stable paths.** Set `KXM_WORKSPACE_DIR`, `KXM_STATE_DIR`, `KXM_DATA_PATH`, `KXM_LOG_PATH` and `KXM_STATE_HOME` instead of inheriting a home directory, and pin `KXM_HOST=127.0.0.1`. `kxm backup` ignores `KXM_STATE_DIR` and `KXM_DATA_PATH`, so on such a box it finds no hub store: it copies only the Runtime stores under `KXM_STATE_HOME`, or fails with `backup_no_stores` when there are none. Copy the hub database with the [stopped-state backup](backup-and-restore.md#back-up-everything-else).
240
+ 2. **Explicit, stable paths.** Set `KXM_WORKSPACE_DIR`, `KXM_STATE_DIR`, `KXM_DATA_PATH`, `KXM_LOG_PATH` and `KXM_STATE_HOME` instead of inheriting a home directory, and pin `KXM_HOST=127.0.0.1`. `kxm backup` ignores `KXM_STATE_DIR` and `KXM_DATA_PATH`, so on such a box it finds no hub store: it copies only the project's Runtime event store under `KXM_STATE_HOME`, or fails with `backup_no_stores` when there is none. Copy the hub database with the [stopped-state backup](backup-and-restore.md#back-up-everything-else).
241
241
  3. **Loopback listeners only.** Neither the hub nor the supervisor has a public port, and nothing is load-balanced across hubs.
242
242
  4. **Edge authentication.** The proxy authenticates browsers (for example with Authentik forward auth) on the portal's routes only. The hub never interprets browser identity; see [ADR-0004](../adr/ADR-0004-edge-identity-authentik.md).
243
243
  5. **Server-side machine credentials.** The portal backend keeps the hub credentials and calls the hub itself. `kxm tenant status`, which uses the admin token, gives it one labelled view of hub metadata and Runtime runs.
@@ -183,7 +183,7 @@ Creates, validates, repairs, resumes, or joins a KXM project at the Git root tha
183
183
  - `--project-id` must match `prj_` followed by 6 to 128 letters, digits, `_`, or `-`. `--repository` is repeatable; each value must be `<id>=<absolute path>`, and a repeated ID fails with `repository_binding_argument_duplicate`.
184
184
  - Needs a Git repository. Does not need a hub or the Runtime.
185
185
  - Writes `.kxm/project.yaml`, `.kxm/agents/coordinator.yaml`, `.kxm/agents/implementer.yaml`, `.kxm/gates.yaml`, `.kxm/repo/repo.yaml`, `.kxm/workflows/default.yaml`, and `.kxm/template-provenance.yaml`, using a `.kxm-init-transaction` directory at the Git root while a create or repair is in flight. Repository bindings are written under the user state root, never into Git. `--dry-run` writes nothing.
186
- - On an interactive terminal without `--json` or `--dry-run`, a successful create or join offers to install shell completion (suppress with `KXM_SKIP_COMPLETION_PROMPT=1`) and to write workflow-guide agents (suppress with `KXM_SKIP_GUIDE_SETUP_PROMPT=1`). Guided setup keeps a role only when one of its guide candidates is on a fixed map of reviewed harness/model pairs and that harness is authenticated; it writes the agent and workflow files, appends those selectors to `.kxm/routes.yaml`, and skips every other candidate. Google candidates map to the Pi `antigravity` provider, which the Runtime's Pi one-shot cannot reach yet (see [Harness routing](harness-routing.md#google-through-the-antigravity-pi-provider)).
186
+ - On an interactive terminal without `--json` or `--dry-run`, a successful create or join offers to install shell completion (suppress with `KXM_SKIP_COMPLETION_PROMPT=1`) and to write workflow-guide agents (suppress with `KXM_SKIP_GUIDE_SETUP_PROMPT=1`). Guided setup keeps a role only when one of its guide candidates is on a fixed map of reviewed harness/model pairs and that harness is authenticated; it writes the agent and workflow files, appends those selectors to `.kxm/routes.yaml`, and skips every other candidate. Google candidates are not on the map and are always skipped, because the Runtime's Pi one-shot cannot reach Google's `antigravity` Pi provider yet (see [Harness routing](harness-routing.md#google-through-the-antigravity-pi-provider)).
187
187
  - JSON keys: `action` (`planned`, `created`, `joined`, `repaired`, `resumed`, or `validated`), `mode`, `inspectedFrom`, `projectRoot`, `changesRequired`, `legacyInputs`, `issues`, `configRevision`, `files`, `plannedOnly`, and, when relevant, `localBindingFile`, `bindingsChanged`, `repairPlan`, `resumePending`, `transactionKind`.
188
188
  - Exit 0 for every completed action and every dry-run plan. Exit 1 when the result is planning-only (legacy state, blocked repair, partial state without provenance) or for `initialization_failed` (with `issues`) and `initialization_io_failed`. A planning-only text result prints the reason and then one `<file>: <code>: <message>` line per validation issue, for example `.kxm/workflows/first.yaml: gate_outcome_impossible: ...`.
189
189
 
@@ -3340,17 +3340,18 @@ price catalog stamped 2026-09-23 (list estimate only; vendor rates were not fetc
3340
3340
  ## `kxm backup`
3341
3341
 
3342
3342
  ```text
3343
- kxm backup [--out <dir>]
3343
+ kxm backup [--out <dir>] [--all-projects]
3344
3344
  ```
3345
3345
 
3346
- Creates a verified SQLite backup of the project hub store and the Runtime stores under the user state root, with a hashed `kxm.backup-manifest.v1` manifest. Relative to the current directory it discovers the hub store `.kxm/state/kxm.db`, and any `registry.db`, `bindings.db`, and `events/*.db` under `.kxm/runtime/`. Under the user state root (`KXM_STATE_HOME` or the platform default) it discovers `runtime/registry.db`, the `run-events.db` of every project under `runtime/projects/`, and each store's `run-events.db.run-prompts.json` prompt sidecar, which it copies as a plain file. Those Runtime stores belong to every project on the machine, not only this one. It ignores `--workspace` and `KXM_DATA_PATH`. Bindings, `update.yaml` and the other state roots are not included; see [Backup and restore](../operations/backup-and-restore.md).
3346
+ Creates a verified SQLite backup of this checkout's hub store and Runtime event store, with a hashed `kxm.backup-manifest.v1` manifest. It acts for the checkout the Runtime would use: the Git root that holds `.kxm/project.yaml`, or the current directory outside one. Under that checkout it discovers the hub store `.kxm/state/kxm.db`, and any `registry.db`, `bindings.db`, and `events/*.db` under `.kxm/runtime/`. Under the user state root (`KXM_STATE_HOME` or the platform default) it discovers the checkout's own `runtime/projects/<key>/run-events.db`, with `<key>` derived from the canonical checkout path as the Runtime derives it, and that store's `run-events.db.run-prompts.json` prompt sidecar, which it copies as a plain file. The shared `runtime/registry.db` and other projects' event stores are left out unless you pass `--all-projects`. It ignores `--workspace` and `KXM_DATA_PATH`. Bindings, `update.yaml` and the other state roots are not included; see [Backup and restore](../operations/backup-and-restore.md).
3347
3347
 
3348
3348
  | Option | Argument | Default | Description |
3349
3349
  |---|---|---|---|
3350
3350
  | `--out` | `<dir>` | `.kxm/backups/backup-<timestamp>` | Directory to write backup and manifest |
3351
+ | `--all-projects` | | Off | Also back up the Runtime registry and the event store and prompt sidecar of every project under `runtime/projects/`. Restoring that backup needs `kxm restore --all-projects` |
3351
3352
 
3352
- - Writes a copy of each store and sidecar and `manifest.json`. `--dry-run` lists the stores and files it found and the files it would write without opening any store, so no WAL is checkpointed (JSON: `outDir`, `stores` with `storeId`, `sourcePath`, `backupFile`, `files` with `id`, `sourcePath`, `backupFile`, plus `dryRun` and `planned`).
3353
- - JSON keys: `ok`, `backupId`, `outDir`, `manifest` (`schema`, `backupId`, `createdAt`, `projectRoot`, `stores` with `storeId`, `sourcePath`, `backupFile`, `schemaVersion`, `sha256`, `bytes`, `integrity`; `files` with `id`, `sourcePath`, `backupFile`, `sha256`, `bytes`; `complete`; `omitted`; `manifestSha256`).
3353
+ - Writes a copy of each store and sidecar and `manifest.json`. `--dry-run` lists the stores and files it found and the files it would write without opening any store, so no WAL is checkpointed (JSON: `scope`, `outDir`, `stores` with `storeId`, `sourcePath`, `backupFile`, `files` with `id`, `sourcePath`, `backupFile`, plus `dryRun` and `planned`).
3354
+ - JSON keys: `ok`, `backupId`, `outDir`, `manifest` (`schema`, `backupId`, `createdAt`, `projectRoot`, `scope` (`project` or `all-projects`), `stateRoot`, `runtimeProjectKey`, `stores` with `storeId`, `sourcePath`, `backupFile`, `schemaVersion`, `sha256`, `bytes`, `integrity`; `files` with `id`, `sourcePath`, `backupFile`, `sha256`, `bytes`; `complete`; `omitted`; `manifestSha256`).
3354
3355
  - A store or sidecar that cannot be copied, or that appears while the backup runs, is listed in `omitted` and the manifest records `complete: false`. The command then prints `Backup is incomplete (<n> omitted); not ok:`, sets `ok: false`, and exits 1; `kxm restore` refuses that manifest.
3355
3356
  - Exit 1 with `backup_failed`; `issues` carry codes such as `backup_no_stores` (no store found, or none could be copied) and `database_corrupted`.
3356
3357
 
@@ -3359,31 +3360,29 @@ kxm backup --out ../bk
3359
3360
  ```
3360
3361
 
3361
3362
  ```text
3362
- Created SQLite backup with 3 store(s):
3363
+ Created SQLite backup with 2 store(s) (project scope):
3363
3364
  - hub-store: /work/proj/.kxm/state/kxm.db -> kxm.db (schema v5, 110592 bytes, sha256 sha256:56c6d...)
3364
- - registry: /home/me/.local/state/kxm/runtime/registry.db -> registry.db (schema v1, 20480 bytes, sha256 sha256:a5bde...)
3365
3365
  - events:38ed26cb8eeaa297f3b0b452: /home/me/.local/state/kxm/runtime/projects/38ed26cb8eeaa297f3b0b452/run-events.db -> run-events.db (schema v7, 348160 bytes, sha256 sha256:27c13...)
3366
3366
  Manifest: /work/bk/manifest.json
3367
3367
  ```
3368
3368
 
3369
3369
  The summary lists stores; the prompt sidecar appears under `files` in the manifest.
3370
3370
 
3371
- In a project with a hub store and one Runtime project:
3371
+ In a project with a hub store and a Runtime event store:
3372
3372
 
3373
3373
  ```bash
3374
3374
  kxm backup --dry-run
3375
3375
  ```
3376
3376
 
3377
3377
  ```text
3378
- dry run: back up 3 store(s) and 1 file(s) to /work/proj/.kxm/backups/backup-2026-09-23T17-44-51-277Z (sources are not opened, so their WAL is not checkpointed)
3378
+ dry run: back up 2 store(s) and 1 file(s) (project scope) to /work/proj/.kxm/backups/backup-2026-09-23T17-44-51-277Z (sources are not opened, so their WAL is not checkpointed)
3379
3379
  would write /work/proj/.kxm/backups/backup-2026-09-23T17-44-51-277Z/kxm.db
3380
- would write /work/proj/.kxm/backups/backup-2026-09-23T17-44-51-277Z/registry.db
3381
3380
  would write /work/proj/.kxm/backups/backup-2026-09-23T17-44-51-277Z/run-events.db
3382
3381
  would write /work/proj/.kxm/backups/backup-2026-09-23T17-44-51-277Z/run-events.db.run-prompts.json
3383
3382
  would write /work/proj/.kxm/backups/backup-2026-09-23T17-44-51-277Z/manifest.json
3384
3383
  ```
3385
3384
 
3386
- On a machine with no hub store and no Runtime stores yet:
3385
+ On a machine with no hub store and no Runtime event store for this checkout yet:
3387
3386
 
3388
3387
  ```bash
3389
3388
  kxm backup --json
@@ -3396,17 +3395,20 @@ kxm backup --json
3396
3395
  ## `kxm restore`
3397
3396
 
3398
3397
  ```text
3399
- kxm restore <manifest>
3398
+ kxm restore <manifest> [--all-projects]
3400
3399
  ```
3401
3400
 
3402
- Restores SQLite stores and prompt sidecars from a verified backup manifest. It checks the manifest schema, refuses a manifest that records `complete: false` (`restore_incomplete`), checks that every backup file is present and each file's digest, then restores each store to its recorded source path, then each sidecar. A path under the manifest's project root is rebased onto the current directory when the manifest came from another project root; Runtime stores under the user state root go back to their recorded absolute paths. A manifest without a `complete` field, from an older build, still restores.
3401
+ Restores SQLite stores and prompt sidecars from a verified backup manifest into the checkout the Runtime would use, found as for `kxm backup`. It checks the manifest schema, refuses a manifest that records `complete: false` (`restore_incomplete`), checks that every backup file is present and each file's digest, and works out each target. A path under the manifest's project root is rebased onto this checkout. The backed-up checkout's own event store and its sidecar go to the store the Runtime derives for this checkout under the current user state root. Anything else under the user state root, such as the registry or another project's event store, is refused with `restore_requires_all_projects` unless you pass `--all-projects`, which rebases it onto the current user state root. A manifest written before backups were scoped records its Runtime stores as bare absolute paths; they count as machine-wide too, and `--all-projects` writes them back to those paths. A manifest without a `complete` field, from an older build, still restores.
3403
3402
 
3404
- - Arguments: `<manifest>`, path to `manifest.json`.
3405
- - No command-specific options.
3406
- - Overwrites live stores, including the Runtime stores of every project the backup holds; it does not check whether the hub or the Runtime is running. Stop both before restoring.
3407
- - Before overwriting anything, a restore checks every store's recorded schema version against the ceiling for that store, so a store newer than this build is refused (`runtime_schema_newer`) before the first file is replaced. `--dry-run` runs the same manifest, file, digest, and schema checks and plans each target it would overwrite (and any `-wal` or `-shm` sidecar it would delete) without touching them. Dry-run JSON keys: `backupId`, `manifestPath`, `stores` (`storeId`, `targetPath`, `schemaVersion`), `files` (`id`, `targetPath`), `dryRun`, `planned`.
3408
- - JSON keys: `backupId`, `manifestPath`, `restoredStores` (`storeId`, `sourcePath`, `backupFile`, `schemaVersion`, `integrity`).
3409
- - Exit 1 with `restore_failed`; `issues` carry codes such as `runtime_path_invalid`, `restore_manifest_invalid`, `restore_incomplete`, `restore_file_missing`, `restore_manifest_digest_mismatch`, and `runtime_schema_newer`.
3403
+ | Option | Argument | Default | Description |
3404
+ |---|---|---|---|
3405
+ | `--all-projects` | | Off | Also restore the Runtime registry and other projects' event stores the backup holds, rolling back every project on the machine |
3406
+
3407
+ - Arguments: `<manifest>`, path to `manifest.json` or the directory that holds it.
3408
+ - Refuses before writing anything while the Runtime supervisor is running (`restore_runtime_running`), judged as `kxm runtime status` judges it but through a read-only open of the registry, and while a live `hub.pid` claim sits beside a hub store it would overwrite (`restore_hub_running`). Stop both first.
3409
+ - Before overwriting anything, a restore checks every store's recorded schema version against the ceiling for that store, so a store newer than this build is refused (`runtime_schema_newer`) before the first file is replaced. `--dry-run` runs the same manifest, file, digest, schema, scope, supervisor and hub checks and plans each target it would overwrite (and any `-wal` or `-shm` sidecar it would delete) without touching them. Dry-run JSON keys: `backupId`, `manifestPath`, `scope`, `stores` (`storeId`, `targetPath`, `schemaVersion`), `files` (`id`, `targetPath`), `dryRun`, `planned`.
3410
+ - JSON keys: `backupId`, `manifestPath`, `scope`, `restoredStores` (`storeId`, `sourcePath`, `backupFile`, `schemaVersion`, `integrity`). `scope` is absent for a manifest written before backups were scoped.
3411
+ - Exit 1 with `restore_failed`; `issues` carry codes such as `runtime_path_invalid`, `restore_manifest_invalid`, `restore_incomplete`, `restore_file_missing`, `restore_manifest_digest_mismatch`, `runtime_schema_newer`, `restore_requires_all_projects`, `restore_runtime_running`, `restore_runtime_unverified` (the registry could not be read to check the supervisor), and `restore_hub_running`.
3410
3412
  - Two more checks run per store while restoring, after the plan checks: a backup file whose schema version differs from the version the manifest records is refused with `runtime_schema_mismatch`, and one that fails its SQLite integrity check with `database_corrupted`. In a multi-store restore, stores restored before the refused one stay restored.
3411
3413
 
3412
3414
  ```bash
@@ -3414,13 +3416,22 @@ kxm restore ../bk/manifest.json --dry-run
3414
3416
  ```
3415
3417
 
3416
3418
  ```text
3417
- dry run: restore 3 store(s) and 1 file(s) from /work/bk/manifest.json; digests verified against the manifest
3419
+ dry run: restore 2 store(s) and 1 file(s) from /work/bk/manifest.json; digests verified against the manifest
3418
3420
  would write /work/proj/.kxm/state/kxm.db
3419
- would write /home/me/.local/state/kxm/runtime/registry.db
3420
3421
  would write /home/me/.local/state/kxm/runtime/projects/38ed26cb8eeaa297f3b0b452/run-events.db
3421
3422
  would write /home/me/.local/state/kxm/runtime/projects/38ed26cb8eeaa297f3b0b452/run-events.db.run-prompts.json
3422
3423
  ```
3423
3424
 
3425
+ While the Runtime supervisor is running:
3426
+
3427
+ ```bash
3428
+ kxm restore ../bk/manifest.json
3429
+ ```
3430
+
3431
+ ```text
3432
+ restore failed: /home/me/.local/state/kxm/runtime/registry.db: restore_runtime_running: the Runtime supervisor is running (pid 48213); stop it with `kxm runtime stop` and keep it stopped until the restore finishes
3433
+ ```
3434
+
3424
3435
  A missing manifest:
3425
3436
 
3426
3437
  ```bash
@@ -459,7 +459,9 @@ Commands: `kxm init` creates `coordinator` (`claude`, `anthropic/fable`) and
459
459
  `implementer` (`grok`, `xai/grok-4.6`) and admits both selectors in
460
460
  `.kxm/routes.yaml`; an interactive `kxm init` can add workflow-guide agents for
461
461
  reviewed harness/model pairs whose harness is authenticated, and admits their
462
- selectors too; `kxm run` and the Runtime read them; `kxm trust` diffs them.
462
+ selectors too, but skips Google guide candidates because the Runtime cannot
463
+ reach the `antigravity` Pi provider yet; `kxm run` and the Runtime read them;
464
+ `kxm trust` diffs them.
463
465
 
464
466
  ## `.kxm/models/<id>.yaml` (`kxm.model.v1`)
465
467
 
@@ -1729,7 +1731,7 @@ Everything under `.kxm/` at the project root falls into one of three groups.
1729
1731
  | `logs/` | Ignored runtime logs | The hub and workers |
1730
1732
  | `state/` | Ignored restart state: the hub database `kxm.db`, Pi sessions, worker manifests | The hub and workers |
1731
1733
  | `run/` | Ignored sockets (`run/ssh-sockets/`) | `kxm ssh` |
1732
- | `backups/` | Ignored; each `backup-<time>/` holds copies of the hub database, the Runtime stores and their prompt sidecars, and `manifest.json` | `kxm backup` (without `--out`) |
1734
+ | `backups/` | Ignored; each `backup-<time>/` holds copies of the hub database, this project's Runtime event store and prompt sidecar (every project's, and the registry, with `--all-projects`), and `manifest.json` | `kxm backup` (without `--out`) |
1733
1735
  | `config/` | Legacy: its JSON files make the project unloadable | Nothing current |
1734
1736
  | `.kxm-init-transaction/` (sibling of `.kxm/` at the Git root) | Ignored; interrupted `kxm init` state | `kxm init` |
1735
1737
 
@@ -380,7 +380,7 @@ A larger context window on the OpenRouter route does not make OpenRouter an allo
380
380
  |---|---|---|---|
381
381
  | Agent YAML | `harness: agy`, `provider: google`, `model: gemini-3.8-flash-high` | `harness:` omitted, `provider: antigravity`, `model: gemini-3.8-flash` | `harness:` omitted, `provider: openrouter`, `model: google/gemini-3.8-flash` |
382
382
  | Selector | `google/gemini-3.8-flash-high` | `antigravity/gemini-3.8-flash` | `openrouter/google/gemini-3.8-flash` |
383
- | Readiness | Needs `agy` auth `yes` (`antigravity-oauth`) | Registered only inside the KXM Pi extension. From a plain shell, `pi auth check --provider antigravity` returns `provider_not_found`. | Never reached: the brake refuses it (vendor segment `google`) |
383
+ | Readiness | Needs `agy` auth `yes` (`antigravity-oauth`) | Registered only by the KXM Pi extension. `pi auth check` never loads extensions, so `pi auth check --provider antigravity` returns `provider_not_found`. | Never reached: the brake refuses it (vendor segment `google`) |
384
384
  | Billing | Google subscription | Google subscription | OpenRouter credit |
385
385
  | Recorded `costBasis` | `unmetered`, `priceRef: subscription:agy` | `unknown` | None: refused before dispatch |
386
386
  | Effort | Part of the id: `-high`, `-medium` or `-low` | A thinking level: `low`, `medium` or `high` | — |
@@ -404,10 +404,10 @@ Google is the one native vendor whose preferred subscription route is a Pi provi
404
404
  The code today limits where that route can run:
405
405
 
406
406
  - Pi brakes the `google` and `google-vertex` providers, so a `google/gemini-…` selector can run only through `agy`.
407
- - The KXM Pi extension registers the `antigravity` provider. The Runtime's Pi one-shot runs with `--no-extensions`, so it cannot reach `antigravity/…`.
407
+ - The KXM Pi extension registers the `antigravity` provider. The Runtime's Pi one-shot runs with `--no-extensions`, and its readiness check, `pi auth check`, never loads extensions, so it cannot reach `antigravity/…`.
408
408
  - Only an interactive Pi with KXM loaded, or a long-lived Pi worker, can use it.
409
409
 
410
- Admit an `antigravity/…` route only through a reviewed admission decision. The guided setup in `kxm init` maps Google guide candidates to `antigravity/gemini-3.8-flash-high` on Pi and admits that selector, but a Runtime drive of such an agent still cannot reach the provider. Whether Google work should use `agy` or `antigravity` today is still an operator decision; see [Where the code is looser than the rules](#where-the-code-is-looser-than-the-rules).
410
+ Admit an `antigravity/…` route only through a reviewed admission decision. The guided setup in `kxm init` does not admit one: it skips every Google guide candidate, so a role falls to its next reviewed candidate or is not written. Whether Google work should use `agy` or `antigravity` today is still an operator decision; see [Where the code is looser than the rules](#where-the-code-is-looser-than-the-rules).
411
411
 
412
412
  ### Claude bridge: experiment only
413
413
 
@@ -460,7 +460,7 @@ Each of those is a fail-closed stop, or a new admission decision.
460
460
  | `grok` shows auth `unknown (auth_unparsed)`. | `grok models` did not print `You are logged in with grok.com.` | Run `grok login --oauth`, then `grok models`. |
461
461
  | `pi` shows `unknown (auth_context_required)`. | This is normal. Pi auth is checked per provider. | Run `pi auth check --provider <id> --json --no-refresh` for the provider you need. |
462
462
  | `pi auth check --provider openrouter` returns `not_ready` with `credentials_not_configured` and exits 1. | No OpenRouter credential where Pi or the Runtime starts. | Run `/login openrouter` inside Pi, or export `OPENROUTER_API_KEY` where the Runtime starts. Then re-check. |
463
- | `pi auth check --provider nous-portal` or `--provider antigravity` returns `provider_not_found`. | The provider comes from a Pi package or the KXM Pi extension, which that process did not load. | Confirm with `pi list` and `pi --list-models <id>`. The Runtime's Pi one-shot runs with `--no-extensions`, so it cannot reach extension providers. |
463
+ | `pi auth check --provider nous-portal` or `--provider antigravity` returns `provider_not_found`. | The provider comes from a Pi package or the KXM Pi extension, and `pi auth check` never loads extensions, not even one passed with `-e`. | Confirm with `pi list` and `pi --list-models <id>`. The Runtime's Pi one-shot runs with `--no-extensions` and checks readiness with `pi auth check`, so it cannot reach extension providers. |
464
464
  | `producer_route_unsupported: model '<selector>' is not admitted`, or `producer_route_not_admitted`. | The selector is missing from `admitted` in `.kxm/routes.yaml`, or it is under `disabled`. | Check with `kxm routes list`. After a reviewed decision, run `kxm routes admit --model <id>`, or edit the file when the inventory lacks the id. |
465
465
  | `producer_route_unsupported: model '<selector>' not in role '<role>' roster` | The role file exists and does not list the selector. | Add it to `.kxm/roles/<role>.yaml` by Git review, and check with `kxm role get <role>`. |
466
466
  | `pi_native_impersonation_blocked`, at dispatch or when a worker starts. | A Pi agent or worker names a native vendor's model: directly, through that vendor's Pi provider, or behind an aggregator. | Use the native harness (`harness: grok` for `provider: xai`), or an admitted Pi route whose vendor has no native harness, such as `openrouter/qwen/qwen3-coder-plus`. |
@@ -493,7 +493,7 @@ These are places where the code decides less than the [routing rules](#routing-r
493
493
  - **Reseller ids without a vendor segment.** Pi also serves native vendors' models under a reseller's own provider id, for example `github-copilot/claude-…`, `amazon-bedrock/anthropic.…` or `azure-openai-responses/gpt-…`. The brake reads the provider and the vendor segment, not the model name, so it accepts these ids. Keep them out of `.kxm/routes.yaml`.
494
494
  - **Open-weight models on a third-party plan.** A DeepSeek model billed through Alibaba's plan, such as `qwen-token-plan/deepseek-v4.1-flash`, passes the brake although DeepSeek is a braked vendor. The reverse also happens: an open-weight model filed under a native vendor's namespace, such as `groq/openai/gpt-oss-120b`, is refused. Whether a third-party plan bill counts as billing the vendor is not decided.
495
495
  - **Selectors the brake cannot see.** A worker started without `--model` runs Pi's default model, and a bare model id lets Pi choose the provider. Neither names a vendor, so neither is checked. A model that a person selects inside an interactive Pi session is not checked either.
496
- - **The Google route.** The rules name the `antigravity` Pi provider as Google's route, and the guided setup in `kxm init` now writes Google roles on Pi with `antigravity/gemini-3.8-flash-high` and admits that selector. The Runtime's Pi one-shot runs with `--no-extensions`, so it cannot reach `antigravity/…` and a live drive of those roles fails at dispatch (section 4). A `google/gemini-…` selector still runs only through `agy`.
496
+ - **The Google route.** The rules name the `antigravity` Pi provider as Google's route, but the Runtime's Pi one-shot cannot reach `antigravity/…` (section 4), and a `google/gemini-…` selector still runs only through `agy`. The guided setup in `kxm init` skips Google guide candidates instead of choosing between the two.
497
497
  - **Two Pi provider allowlists.** `PI_ALLOWED_PROVIDERS` in `plugins/kxm/src/harness.ts` is exported but gates nothing; on the product path, the brake and admission in `.kxm/routes.yaml` decide. The developer helper keeps a different list of its own.
498
498
  - **`limits.maxModelCost` cannot trip on a live run.** The engine counts only `metered` cost toward the cap, and no producer records `metered` today (section 2). The Runtime caps `unmetered` and `unknown` attempts at 100 per run instead; see [Cost basis and staleness](config-reference.md#cost-basis-and-staleness).
499
499
  - **Config load checks harness/model pairs only for agents that declare `harness:` and select their model through a profile or tag.** An agent with a direct `{provider, model}` selector, or one that omits `harness:` and names `provider: xai`, passes `kxm init --dry-run` and fails only at dispatch.
@@ -26,7 +26,7 @@ The catalog is a four-level taxonomy: **Area → Workflow → Stage → Role**.
26
26
  - **Selection is per role.** Areas are navigation only; they never pool unrelated roles into one ranking. Model, harness, platform, modality and required tools are routing attributes, not areas.
27
27
  - **Gates stay deterministic.** Where a role is a critic next to a gate, the gate (tests, type checks, linters) decides pass or fail, and the model reviews what a gate cannot check.
28
28
 
29
- An interactive `kxm init` offers to install the Software Engineering workflows when at least one harness is signed in. For each role it picks the first candidate whose harness is installed and signed in, and writes one agent file per role and one `kxm.workflow.v1` file per workflow you choose. Existing files are kept. Set `KXM_SKIP_GUIDE_SETUP_PROMPT=1` to skip the offer.
29
+ An interactive `kxm init` offers to install the Software Engineering workflows when at least one harness is signed in. For each role it picks the first candidate that is on KXM's reviewed harness/model map and whose harness is installed and signed in (Google candidates are skipped for now), and writes one agent file per role and one `kxm.workflow.v1` file per workflow you choose. Existing files are kept. Set `KXM_SKIP_GUIDE_SETUP_PROMPT=1` to skip the offer.
30
30
 
31
31
  ### Cost bands (dated candidates)
32
32
 
@@ -331,7 +331,7 @@ kxm runtime stop
331
331
  `kxm backup` writes a verified copy and a hashed manifest to `.kxm/backups/backup-<timestamp>/`.
332
332
 
333
333
  > [!WARNING]
334
- > `kxm backup` copies the hub store and the Runtime's registry and run event stores, and those Runtime stores belong to every project on this machine. A later `kxm restore` rolls all of them back. It does not copy bindings, `update.yaml` or the other state roots; [Back up everything else](../operations/backup-and-restore.md#back-up-everything-else) covers those.
334
+ > `kxm backup` copies this project's hub store and its Runtime run event store. The Runtime registry and other projects' run stores are shared by every project on this machine, so they are copied only with `--all-projects`, and a later `kxm restore` refuses to roll them back without the same flag. It does not copy bindings, `update.yaml` or the other state roots; [Back up everything else](../operations/backup-and-restore.md#back-up-everything-else) covers those.
335
335
 
336
336
  [Back up and restore KXM](../operations/backup-and-restore.md) and [Upgrade KXM](../operations/upgrade.md) cover restores and rollback.
337
337
 
@@ -77,5 +77,6 @@ flowchart TD
77
77
  ## Rollback and escalation
78
78
 
79
79
  - **Rollback:** restore the last verified backup with
80
- `kxm restore <manifest>` while the hub is stopped.
80
+ `kxm restore <manifest>` while the hub and the Runtime are stopped; it
81
+ refuses while either is running.
81
82
  - **Escalation:** <primary on-call or human operator contact>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextmind/kxm",
3
- "version": "0.7.102",
3
+ "version": "0.7.104",
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.102",
5
+ "version": "0.7.104",
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",