@kontextmind/kxm 0.7.180 → 0.7.182
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 +23 -0
- package/docs/architecture/authentication.md +11 -2
- package/docs/architecture/hosted-direction.md +7 -5
- package/docs/architecture/inventory.md +5 -3
- package/docs/architecture/platform.md +18 -4
- package/docs/contributing/ci-and-release.md +18 -9
- package/docs/contributing/decisions.md +31 -0
- package/docs/contributing/development.md +39 -1
- package/docs/contributing/test-matrix.md +2 -1
- package/docs/reference/cli-reference.md +9 -9
- package/docs/reference/configuration.md +22 -0
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +148 -42
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/improve-sources.ts +99 -13
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/studio-layout.ts +50 -0
- package/scripts/ci-postgres-17.sh +144 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,20 @@ All notable user-facing changes are documented here. The project follows [Semant
|
|
|
6
6
|
|
|
7
7
|
### Added
|
|
8
8
|
|
|
9
|
+
- **The witnessed MG1 Python control-plane foundation is now reproducible from this repository.**
|
|
10
|
+
`python/kxm-control` provides the pinned Python 3.13 uv workspace, fixed
|
|
11
|
+
`kxmd` Postgres/Temporal caller, Authentik user and runner verification
|
|
12
|
+
that requires token expiry, tenant/project/repository registration,
|
|
13
|
+
owner/admin tenant rename, revision and artifact APIs, and a probe entry
|
|
14
|
+
point. OpenAPI and the Studio path inventory are derived from the FastAPI
|
|
15
|
+
app. The checked generator emits the revision helper. Studio exposes the
|
|
16
|
+
bounded `/api/control/account` relay with a three-second bound and explicit
|
|
17
|
+
failure states. Removing registration leaves source state untouched and
|
|
18
|
+
later registry calls return `registration_unavailable` until the schema is
|
|
19
|
+
installed again. The package does not change host or guest installs. The
|
|
20
|
+
required CI aggregate runs the Python contracts against PostgreSQL 17. This
|
|
21
|
+
does not move the hub or Runtime from their existing Node and SQLite owners.
|
|
22
|
+
|
|
9
23
|
- **KXM configuration now has one owner-validated terminal editor.**
|
|
10
24
|
`kxm config edit --scope project|user` and OMP/Pi `/kxm config` publish the
|
|
11
25
|
same `kxm.config.v1` surface. Accepted writes are saved and re-read; rejected
|
|
@@ -651,6 +665,15 @@ All notable user-facing changes are documented here. The project follows [Semant
|
|
|
651
665
|
|
|
652
666
|
### Fixed
|
|
653
667
|
|
|
668
|
+
- **`kxm improve report` and `kxm routing report` include attempts settled in a registered lane.**
|
|
669
|
+
Inside a KXM project, a present user-state `registry.db` is opened read-only at schema version 2. One query loads the home row and every lane row for that project id. Event-store paths come from the stored project keys, so a stale checkout path cannot hide a lane. A missing store stays a zero-record source. An absent registry, or a checkout that is not registered, still reads only that checkout's own store. `--file` still reads only the named file. See
|
|
670
|
+
[kxm improve report](docs/reference/cli-reference.md#kxm-improve-report).
|
|
671
|
+
|
|
672
|
+
- **Browser integration tests isolate the Steel credential environment.**
|
|
673
|
+
Each test restores the operator's variables afterward, so ambient Authentik
|
|
674
|
+
credentials cannot override a case that deliberately exercises the legacy
|
|
675
|
+
API-key path.
|
|
676
|
+
|
|
654
677
|
- **`kxm supervise` keeps supervisor state across a restart.**
|
|
655
678
|
`status`, `record`, and `tick` store in-flight lanes, the last-seen pull
|
|
656
679
|
request and CI state, and backoff timers in `.kxm/state/supervisor.json`.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Authentication
|
|
2
2
|
|
|
3
|
-
Read from `plugins/kxm/src/harness.ts
|
|
4
|
-
|
|
3
|
+
Read from `plugins/kxm/src/harness.ts`, `plugins/kxm/src/cli.ts`, and
|
|
4
|
+
`python/kxm-control/src/kxm_control/auth.py`.
|
|
5
5
|
`kxm harness list` runs `probeHarnesses` (`cmdHarnessList` in
|
|
6
6
|
`plugins/kxm/src/cli/project.ts`). For each detected harness that has
|
|
7
7
|
`authArgs`, `probeEntry` runs that command and `interpretAuth` reads the
|
|
@@ -23,6 +23,15 @@ the harness command's own stdout.
|
|
|
23
23
|
issues, or clears the local session token file. That token is a KXM session
|
|
24
24
|
token, not a provider key. Provider logins stay in each harness.
|
|
25
25
|
|
|
26
|
+
The MG1 Python control API uses a separate Authentik boundary. It accepts only
|
|
27
|
+
RS256 tokens whose issuer and audience match its configured values, whose
|
|
28
|
+
`exp` is present and unexpired, and whose `kxm_actor` is `user` or `runner`.
|
|
29
|
+
A token without `exp` is rejected.
|
|
30
|
+
The signed subject and actor kind must match
|
|
31
|
+
an explicit tenant membership; a user membership never authorizes a runner
|
|
32
|
+
token with the same subject. Only a user can create a tenant. The API does not
|
|
33
|
+
store the bearer token.
|
|
34
|
+
|
|
26
35
|
## Related
|
|
27
36
|
|
|
28
37
|
- [Access](access.md)
|
|
@@ -52,11 +52,13 @@ roadmap question. The tracker wins.
|
|
|
52
52
|
proposal is not in this repository. Its delivery position is unchanged:
|
|
53
53
|
none of the delivery is scheduled there.
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
Today the Node hub and Runtime still write local SQLite and local files. The
|
|
56
|
+
checked-in MG1 Python control API is the narrow exception: it owns only central
|
|
57
|
+
registration and bounded tenant artifacts in the fixed `kxmd` PostgreSQL
|
|
58
|
+
account. Temporal is provisioned for `kxmd`, but no production workflow cutover
|
|
59
|
+
is selected. Redis Streams, NATS, raw WebSockets, the A2A Python SDK, and S3
|
|
60
|
+
remain backlog. The rest of this page remains a target, not a live deployment
|
|
61
|
+
description.
|
|
60
62
|
|
|
61
63
|
## Related
|
|
62
64
|
|
|
@@ -6,7 +6,8 @@ Read from `plugins/kxm/src/cli.ts`, `plugins/kxm/src/config-editor.ts`,
|
|
|
6
6
|
`plugins/kxm/src/runtime-paths.ts`, `plugins/kxm/src/mcp-server.ts`,
|
|
7
7
|
`plugins/kxm/src/oneshot-producer.ts`, `plugins/kxm/src/studio-layout.ts`,
|
|
8
8
|
`plugins/kxm/src/cli/types.ts` (`workspaceDirs`),
|
|
9
|
-
`plugins/kxm/src/local-snapshot.ts`,
|
|
9
|
+
`plugins/kxm/src/local-snapshot.ts`, `scripts/kxm-worker.mjs`, and
|
|
10
|
+
`python/kxm-control/src/kxm_control/{api,registry}.py`.
|
|
10
11
|
|
|
11
12
|
| Surface | Started by | Listener or path | Store it owns | Defining file |
|
|
12
13
|
| --- | --- | --- | --- | --- |
|
|
@@ -17,11 +18,12 @@ Read from `plugins/kxm/src/cli.ts`, `plugins/kxm/src/config-editor.ts`,
|
|
|
17
18
|
| Hub cloud binding | `kxm hub bind <url> --cloud --token-env/--token-command` | no listener; writes the binding record and never stores the token | binding record; token stays in the named env or command | `plugins/kxm/src/cli/hub.ts` |
|
|
18
19
|
| Runtime supervisor | `kxm runtime` / `scripts/kxm-runtime-supervisor.mjs` | `127.0.0.1` and the requested port, or ephemeral | registry and event stores below | `plugins/kxm/src/runtime-supervisor.ts` |
|
|
19
20
|
| Runtime registry | opened by the supervisor | `runtime/registry.db` under the user state root | `registry.db`. A lane worktree registers under its project: same project id, its own control root, `lane_of` set. A registering root is the primary worktree when its git common dir is `<root>/.git`; if that primary registers while the live home row is not primary, the primary becomes the home row and every other live row of that repository becomes its lane. | `plugins/kxm/src/runtime-paths.ts` |
|
|
20
|
-
| Runtime event store | opened by the supervisor | `runtime/projects/<key>/run-events.db` | `run-events.db` | `plugins/kxm/src/runtime-paths.ts` |
|
|
21
|
+
| Runtime event store | opened by the supervisor | `runtime/projects/<key>/run-events.db` | `run-events.db`. `kxm improve report` and `kxm routing report` read the home store and every lane store for the registered project id through one read-only query of `registry.db` (`plugins/kxm/src/improve-sources.ts`). An absent registry, or a checkout that is not registered, reads only that checkout's own store. Paths come from the stored project keys. | `plugins/kxm/src/runtime-paths.ts` |
|
|
21
22
|
| MCP server | Claude plugin or stdio launch | stdio | none | `plugins/kxm/src/mcp-server.ts` |
|
|
22
23
|
| One-shot harness | supervisor producer | child process, no listener | none | `plugins/kxm/src/oneshot-producer.ts` |
|
|
23
24
|
| Pi worker | `kxm agent worker` | no HTTP listener in `scripts/kxm-worker.mjs` | none of its own | `scripts/kxm-worker.mjs` |
|
|
24
|
-
| Studio | `kxm studio serve` | `127.0.0.1:4242` | none | `plugins/kxm/src/studio-layout.ts` |
|
|
25
|
+
| Studio | `kxm studio serve` | `127.0.0.1:4242` | none; `/api/control/account` is a bounded relay to the configured control API | `plugins/kxm/src/studio-layout.ts` |
|
|
26
|
+
| Python control API | ASGI server loading `kxm_control.api:app` | deployment-selected; the package declares no network default | `kxm_registry` in the fixed `kxmd` PostgreSQL database and the configured tenant artifact root | `python/kxm-control/src/kxm_control/api.py` |
|
|
25
27
|
| Workspace config | `workspaceDirs` | `.kxm/config`, or `KXM_CONFIG_DIR` | files in that directory | `plugins/kxm/src/cli/types.ts` |
|
|
26
28
|
| Workspace logs | `workspaceDirs` | `.kxm/logs`, or `KXM_LOGS_DIR` | log files | `plugins/kxm/src/cli/types.ts` |
|
|
27
29
|
| Workspace assets | `workspaceDirs` | `.kxm/assets`, or `KXM_ASSETS_DIR` | asset files | `plugins/kxm/src/cli/types.ts` |
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Read from `plugins/kxm/src/cli.ts`, `plugins/kxm/src/runtime-supervisor.ts`,
|
|
4
4
|
`scripts/kxm-hub.mjs`, `plugins/kxm/src/hub.ts`, `plugins/kxm/src/mcp-server.ts`,
|
|
5
|
-
|
|
5
|
+
`plugins/kxm/src/oneshot-producer.ts`, and
|
|
6
|
+
`python/kxm-control/src/kxm_control/api.py`.
|
|
6
7
|
|
|
7
8
|
KXM on this checkout is local-first. The `kxm` CLI is the operator entry
|
|
8
9
|
(`plugins/kxm/src/cli.ts`, launched through `scripts/kxm.mjs`). The hub is an
|
|
@@ -18,17 +19,29 @@ requested. The MCP server (`plugins/kxm/src/mcp-server.ts`) uses
|
|
|
18
19
|
spawned by the producer registered in `plugins/kxm/src/oneshot-producer.ts`.
|
|
19
20
|
That child process is not a listener.
|
|
20
21
|
|
|
22
|
+
The checked-in MG1 Python control API is additive. It owns central registration
|
|
23
|
+
and bounded tenant artifacts through the fixed `kxmd` account. Only an owner
|
|
24
|
+
or admin membership can rename a tenant. Removing the registration schema
|
|
25
|
+
leaves source state in place, and later registry routes return
|
|
26
|
+
`registration_unavailable` until the schema is installed again. The API does
|
|
27
|
+
not install or change host or guest software. It does not replace the Node
|
|
28
|
+
hub, Runtime, CLI, or their SQLite stores. Studio can relay
|
|
29
|
+
`GET /api/control/account` to this service when `KXM_CONTROL_URL` is configured.
|
|
30
|
+
|
|
21
31
|
```mermaid
|
|
22
32
|
flowchart LR
|
|
23
33
|
cli["kxm CLI"]
|
|
24
|
-
hub["hub"]
|
|
25
|
-
sup["Runtime supervisor"]
|
|
34
|
+
hub["Node hub"]
|
|
35
|
+
sup["Node Runtime supervisor"]
|
|
26
36
|
mcp["MCP server"]
|
|
27
37
|
shot["one-shot harness"]
|
|
38
|
+
studio["Studio"]
|
|
39
|
+
control["MG1 Python control API"]
|
|
28
40
|
cli -->|"kxm hub start"| hub
|
|
29
41
|
mcp -->|"HTTP to hub"| hub
|
|
30
42
|
cli -->|"kxm run"| sup
|
|
31
43
|
sup -->|"spawn producer"| shot
|
|
44
|
+
studio -->|"bounded account read"| control
|
|
32
45
|
```
|
|
33
46
|
|
|
34
47
|
## Listeners
|
|
@@ -39,7 +52,8 @@ flowchart LR
|
|
|
39
52
|
| Supervisor HTTP | `127.0.0.1` and an ephemeral port when the requested port is `0` |
|
|
40
53
|
| MCP | stdio, no TCP port |
|
|
41
54
|
| CLI and one-shot harness | no listener |
|
|
42
|
-
| Studio, when served | `127.0.0.1:4242` from `createStudioServer` in `plugins/kxm/src/studio-layout.ts` |
|
|
55
|
+
| Studio, when served | `127.0.0.1:4242` from `createStudioServer` in `plugins/kxm/src/studio-layout.ts`; its optional control relay targets `KXM_CONTROL_URL` |
|
|
56
|
+
| Python control API | ASGI listener selected by deployment; the package declares no host or port default |
|
|
43
57
|
| Antigravity OAuth callback | loopback port `51121` only during login (`plugins/kxm/src/providers/antigravity/auth/oauth.ts`) |
|
|
44
58
|
|
|
45
59
|
## Related
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# CI and release
|
|
2
2
|
|
|
3
|
-
Pull requests run lint, typecheck,
|
|
4
|
-
Pushes to `main` also run
|
|
3
|
+
Pull requests run lint, typecheck, the Node unit suite on Linux Node 24, and
|
|
4
|
+
the Python control-plane suite against PostgreSQL 17. Pushes to `main` also run
|
|
5
|
+
the Node suite and the full OS × Node matrix.
|
|
5
6
|
The complete suite with coverage floors runs nightly, every merge to `main`
|
|
6
7
|
cuts a patch release, and every release is verified before it reaches npm.
|
|
7
8
|
This page explains which checks run where, how a merge becomes a published
|
|
@@ -15,7 +16,7 @@ release and an npm publish; the nightly job adds the slower suites.
|
|
|
15
16
|
|
|
16
17
|
```mermaid
|
|
17
18
|
flowchart LR
|
|
18
|
-
PR[Pull request] -->|"
|
|
19
|
+
PR[Pull request] -->|"Node shards, Python/Postgres, docs lint, plugin validation"| REQ["CI / required"]
|
|
19
20
|
REQ --> MERGE{Merged?}
|
|
20
21
|
MERGE -->|yes| MAIN[main]
|
|
21
22
|
MAIN -->|"unit shards plus validate:pr matrix"| PUSH[Push CI]
|
|
@@ -40,6 +41,7 @@ together.
|
|
|
40
41
|
| Pull request, push to `main`, or manual | `ci.yml` (`required`) | Aggregates the lanes below into one pass/fail check named `CI / required` |
|
|
41
42
|
| Pull request and push | `ci.yml` (Docs lint) | `lint:docs` and `check:versions`, always |
|
|
42
43
|
| Code pull request and code push | `ci.yml` (Unit engine and Unit, Linux Node 24) | `engine.test.ts` split by test name; `permission.test.ts`, `runtime.test.ts`, and `package-install.test.ts` one file at a time; every other unit file in two light shards. Typecheck and `check-generated` run on `light-1` |
|
|
44
|
+
| Code pull request and code push | `ci.yml` (Python control plane) | Python 3.13 `unittest` contracts from the frozen uv workspace against PostgreSQL 17 started by `scripts/ci-postgres-17.sh` |
|
|
43
45
|
| Platform-sensitive pull request | `ci.yml` (Unit, Windows Node 24) | The same unit lanes on `windows-latest` |
|
|
44
46
|
| Push to `main`, or manual | `ci.yml` (Validate matrix) | `validate:pr` on Linux and Windows for Node 22.19.0 and Node 24; not on a pull request |
|
|
45
47
|
| Code pull request and code push | `ci.yml` (Plugin validation) | `claude plugin validate --strict` on the marketplace and the plugin |
|
|
@@ -73,7 +75,8 @@ What moved off the pull-request lane, and what did not:
|
|
|
73
75
|
runs `validate:pr` on Windows.
|
|
74
76
|
- Coverage, `test/simulations`, and `npm pack --dry-run` stay in the nightly
|
|
75
77
|
complete suite. They were not part of pull-request CI before this split.
|
|
76
|
-
- Plugin validation still
|
|
78
|
+
- Python control-plane validation and Plugin validation still run on code pull
|
|
79
|
+
requests and code pushes.
|
|
77
80
|
|
|
78
81
|
Run `npm run verify` locally before every push. A nightly failure is a release
|
|
79
82
|
blocker: it is the only place the simulation suite and coverage floors run.
|
|
@@ -82,8 +85,13 @@ blocker: it is the only place the simulation suite and coverage floors run.
|
|
|
82
85
|
|
|
83
86
|
Code pull requests run Docs lint, two Linux Node 24 engine shards, a serial
|
|
84
87
|
lane (`permission.test.ts`, then `runtime.test.ts`, then
|
|
85
|
-
`package-install.test.ts`), two light shards for every other unit file,
|
|
86
|
-
|
|
88
|
+
`package-install.test.ts`), two light shards for every other Node unit file,
|
|
89
|
+
the Python 3.13 control-plane suite against PostgreSQL 17, and Plugin
|
|
90
|
+
validation. The Python lane stays on `kontextmind-doks`. That scale set has
|
|
91
|
+
no container-engine socket, so the job starts PostgreSQL 17 with
|
|
92
|
+
`scripts/ci-postgres-17.sh` on `127.0.0.1:5432` and uses the same admin and
|
|
93
|
+
test DSNs as the contributor procedure in [Develop KXM](development.md).
|
|
94
|
+
`light-1` typechecks and checks generated bundles.
|
|
87
95
|
`engine.test.ts` is split by test name because that file alone was 174
|
|
88
96
|
seconds; the serial lane keeps the next longest files off the light pool,
|
|
89
97
|
which was 268 seconds when every non-engine file shared one job.
|
|
@@ -165,9 +173,10 @@ workaround.
|
|
|
165
173
|
The first job, Classify changes, lists the changed paths and sets `code=false`
|
|
166
174
|
when every path matches `*.md` (including `plans/**/*.md`), `docs/**`,
|
|
167
175
|
`.kxm/assets/**`, `LICENSE`, the issue and PR templates, or `dependabot.yml`.
|
|
168
|
-
A non-markdown file under `plans/` is code. Unit lanes,
|
|
169
|
-
and the Validate matrix are skipped. Docs lint runs,
|
|
170
|
-
passes. `scripts/ci-classify.mjs` and
|
|
176
|
+
A non-markdown file under `plans/` is code. Unit lanes, the Python control-plane
|
|
177
|
+
lane, Plugin validation, and the Validate matrix are skipped. Docs lint runs,
|
|
178
|
+
and `CI / required` passes. `scripts/ci-classify.mjs` and
|
|
179
|
+
`ci-contract.test.ts` pin this behavior.
|
|
171
180
|
|
|
172
181
|
`platform=true` when a path is a package manifest, the lockfile, a file under
|
|
173
182
|
`scripts/` or `.github/workflows/`, or a filename that names path, process,
|
|
@@ -198,3 +198,34 @@ Evidence: Evidence: `git diff HEAD origin/main` on the stale branch showed upstr
|
|
|
198
198
|
- Interim recommendation: use the opt-in installer until OMP exposes a
|
|
199
199
|
first-class transactional status-preset API.
|
|
200
200
|
Evidence: `plugins/kxm/src/cli/plugins.ts`, `plugins/kxm/src/session-work.ts`, and `test/core/cli.test.ts`.
|
|
201
|
+
|
|
202
|
+
## 2026-10-11 — Bring the witnessed MG1 Python foundation onto main (migration)
|
|
203
|
+
|
|
204
|
+
- Context: the tracker records MG1 as passed off-repo while the operator's
|
|
205
|
+
primary checkout holds the matching untracked Python workspace, MG0 evidence,
|
|
206
|
+
and Studio control-account proxy. Leaving the implementation outside Git
|
|
207
|
+
makes the recorded gate irreproducible and blocks MG2 from a reviewed base.
|
|
208
|
+
- Options:
|
|
209
|
+
- Keep MG1 off-repo and start the roadmap's role-authority work — weight 0.2.
|
|
210
|
+
Avoids a CI change, but preserves the tracker/source contradiction and risks
|
|
211
|
+
losing the only implementation matching the deployed witness.
|
|
212
|
+
- Import MG1 at `python/kxm-control`, keep Node as the current product owner,
|
|
213
|
+
and add a required Python/PostgreSQL contract lane — weight 0.9. Makes the
|
|
214
|
+
accepted foundation reproducible without claiming a Python cutover.
|
|
215
|
+
- Replace the Node CLI and Runtime with the Python package now — weight 0.1.
|
|
216
|
+
MG2 through MG8 are still open, so this would skip import, bridge, runner,
|
|
217
|
+
parity, and retirement gates.
|
|
218
|
+
- Selected: import the bounded MG1 foundation and its evidence, harden the
|
|
219
|
+
Studio proxy, and make the Python unit/contract suite part of `CI / required`.
|
|
220
|
+
SQLite and the Node Runtime remain authoritative. OpenAPI and the Studio
|
|
221
|
+
path inventory are derived from the FastAPI app; the checked generator emits
|
|
222
|
+
the revision helper. The package does not change host or guest installs.
|
|
223
|
+
After registration removal, registry routes return `registration_unavailable`
|
|
224
|
+
until the schema is installed again.
|
|
225
|
+
- Solid recommendation: keep every accepted migration wave in Git with its
|
|
226
|
+
generated contracts and a required service-backed test lane.
|
|
227
|
+
- Interim recommendation: if the service lane is unavailable, do not merge the
|
|
228
|
+
Python source; retain the off-repo tracker wording rather than claiming an
|
|
229
|
+
unverified gate.
|
|
230
|
+
Evidence: `plans/implementation-plan.md`, `plans/plan-python-migration.md`,
|
|
231
|
+
`python/kxm-control/tests/test_mg1.py`, and `.github/workflows/ci.yml`.
|
|
@@ -23,7 +23,10 @@ extension, the Claude Code plugin, or the bundled skills.
|
|
|
23
23
|
`kxm lane run <unit> --brief <file> --workflow implement-only`.
|
|
24
24
|
The read-only critic workflows on the same command are
|
|
25
25
|
`review-arch-only` and `review-cli-only`.
|
|
26
|
-
- Docker for the clean-container install smoke
|
|
26
|
+
- Docker for the clean-container install smoke and the Python control-plane
|
|
27
|
+
contract suite.
|
|
28
|
+
- Python 3.13 and [`uv`](https://docs.astral.sh/uv/) for the Python
|
|
29
|
+
control-plane contract suite.
|
|
27
30
|
|
|
28
31
|
## Set up a checkout
|
|
29
32
|
|
|
@@ -255,6 +258,41 @@ It runs three scripts in order:
|
|
|
255
258
|
| 2 | `npm run check` | `tsc --noEmit`, `markdownlint-cli2`, and version surfaces |
|
|
256
259
|
| 3 | `npm run check:generated` | Generated artifacts are tracked and match the staged copy |
|
|
257
260
|
|
|
261
|
+
Changes to the Python control plane also run its frozen-workspace contract
|
|
262
|
+
suite before the npm gate. The suite drops and recreates `kxm_mg1_test`, so
|
|
263
|
+
the admin DSN account needs database create and drop privilege. The `postgres`
|
|
264
|
+
superuser in the container below is that account. Run PostgreSQL 17 in a
|
|
265
|
+
disposable container published only on loopback `127.0.0.1:5432`, with
|
|
266
|
+
`POSTGRES_PASSWORD=postgres`. Leave port `5432` on loopback free. Wait until
|
|
267
|
+
`pg_isready` succeeds, export the two DSNs CI uses, run the frozen suite, and
|
|
268
|
+
remove the container afterward:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
docker rm -f kxm-mg1-pg >/dev/null 2>&1 || true
|
|
272
|
+
docker run --detach --name kxm-mg1-pg \
|
|
273
|
+
--publish 127.0.0.1:5432:5432 \
|
|
274
|
+
--env POSTGRES_PASSWORD=postgres \
|
|
275
|
+
postgres:17
|
|
276
|
+
for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30; do
|
|
277
|
+
docker exec kxm-mg1-pg pg_isready -U postgres && break
|
|
278
|
+
sleep 1
|
|
279
|
+
done
|
|
280
|
+
docker exec kxm-mg1-pg pg_isready -U postgres
|
|
281
|
+
export KXM_MG1_ADMIN_DSN='host=127.0.0.1 port=5432 dbname=postgres user=postgres password=postgres'
|
|
282
|
+
export KXM_MG1_TEST_DSN='host=127.0.0.1 port=5432 dbname=kxm_mg1_test user=postgres password=postgres'
|
|
283
|
+
uv run --project python --frozen python -m unittest discover -s python/kxm-control/tests
|
|
284
|
+
suite_status=$?
|
|
285
|
+
docker rm -f kxm-mg1-pg
|
|
286
|
+
(exit "$suite_status")
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
The required CI aggregate repeats that suite against PostgreSQL 17 with the
|
|
290
|
+
same two DSNs and the same `postgres` superuser. On the `kontextmind-doks`
|
|
291
|
+
runners, `scripts/ci-postgres-17.sh` starts that server on `127.0.0.1:5432`
|
|
292
|
+
from a pinned PostgreSQL 17 binary. Contributors use the `postgres:17`
|
|
293
|
+
container procedure above, which publishes the same port and DSNs. The suite
|
|
294
|
+
remains a CI lane rather than a third root gate script.
|
|
295
|
+
|
|
258
296
|
Every suite script passes `--test-force-exit`, and `scripts/run-bounded.mjs` stops the run if the suite is still going after its wall-clock limit (20 minutes, or 40 for the complete and coverage suites). The bound is that wall clock per script. A per-test timeout is not used because under `node --test` each file is itself a test, so a per-test timeout also bounds each file.
|
|
259
297
|
|
|
260
298
|
Other scripts you will use:
|
|
@@ -84,6 +84,7 @@ to run one file is in [Develop KXM](development.md#run-one-file-or-one-test).
|
|
|
84
84
|
| Promotion needs the configured admin token with no loopback bypass; proposed items never reach a packet | `e5-memory-floor.test.ts` |
|
|
85
85
|
| `kxm memory`: candidates, marker-delimited sync blocks, and one brief across CLI, Pi and the Claude hook | `e5b-harness-agnostic-memory.test.ts` |
|
|
86
86
|
| `kxm improve report` reads Runtime-settled attempts, drops simulated and duplicate ones, and flags only same-ask repeats | `improve.test.ts` ("kxm improve report resolves Runtime-settled attempts from the event log and flags only same-ask cross-run repeats"), `cli.test.ts`, `cli-experience.test.ts`, `commands-policy.test.ts` |
|
|
87
|
+
| A registered lane's attempt appears in `kxm improve report` and `kxm routing report` run from the primary checkout; a duplicate still drops and `--file` stays isolated | `improve.test.ts` ("kxm improve report and kxm routing report from the primary include an attempt recorded only in a registered lane") |
|
|
87
88
|
| Improvement candidates exclude write steps; promotion readiness never authorizes | `improve.test.ts` |
|
|
88
89
|
| Telemetry classification and JSONL recovery | `telemetry.test.ts`, `cli.test.ts` |
|
|
89
90
|
|
|
@@ -100,7 +101,7 @@ The context suites in detail:
|
|
|
100
101
|
| `wiki.test.ts` | Wiki compilation determinism, lifecycle preservation, contradiction visibility, lint |
|
|
101
102
|
| `skills.test.ts` | Skill candidate lifecycle, quarantine, immutability, CLI |
|
|
102
103
|
| `routing.test.ts` | Behavioral hash, record parsing, comparisons, `kxm routing report` |
|
|
103
|
-
| `improve.test.ts` | Routing-record sources, event-log outcomes, same-ask candidacy, candidate files, promotion readiness |
|
|
104
|
+
| `improve.test.ts` | Routing-record sources, registered lane stores, event-log outcomes, same-ask candidacy, candidate files, promotion readiness |
|
|
104
105
|
|
|
105
106
|
## Claude Code plugin and MCP
|
|
106
107
|
|
|
@@ -3499,21 +3499,21 @@ Proposes coded-repeat candidates from this project's Runtime routing records and
|
|
|
3499
3499
|
kxm improve report [--file <path>] [--out-dir <path>]
|
|
3500
3500
|
```
|
|
3501
3501
|
|
|
3502
|
-
Generate the improvement report and candidates from routing records. Inside a KXM project (the current directory's Git root holds `.kxm/project.yaml`) it reads
|
|
3502
|
+
Generate the improvement report and candidates from routing records. Inside a KXM project (the current directory's Git root holds `.kxm/project.yaml`) it reads that project's Runtime event stores, then `telemetry.jsonl` in the workspace logs directory; `--file` reads only the named file. Routing records (`kxm.routing-record.v1` and `v2`, bare or nested under `routing`, `envelope.routing`, or a `routing.attempt.recorded` event) are grouped by workflow, step, agent role, and ask. Groups that qualify become proposed candidates, each written as a `.diff` and a `.json` file. Nothing is applied.
|
|
3503
3503
|
|
|
3504
3504
|
| Option | Argument | Default | Description |
|
|
3505
3505
|
|---|---|---|---|
|
|
3506
|
-
| `--file` | `<path>` | the Runtime
|
|
3506
|
+
| `--file` | `<path>` | the Runtime stores, then `.kxm/logs/telemetry.jsonl` | Read only this routing-record JSONL instead of the project's Runtime stores and telemetry |
|
|
3507
3507
|
| `--out-dir` | `<path>` | `<project>/.kxm/candidates` | Directory for candidates (default .kxm/candidates) |
|
|
3508
3508
|
|
|
3509
|
-
-
|
|
3510
|
-
- A telemetry record whose `attemptId`
|
|
3509
|
+
- Each Runtime store is `<state root>/runtime/projects/<key>/run-events.db`. When `runtime/registry.db` is absent, or this checkout's project key is not in it, the command reads only the store derived from this checkout's real path and does not create the registry. When the registry is present and this checkout is registered, it is opened read-only with no migration and no write lock, requires schema version 2, and one query returns the home row and every lane row for that project id. The home store is listed first, then lanes by registration time and key. Store paths are built from those stored keys and `runtime/projects`, not from the checkout path saved on the row, so a stale path cannot change the key. A missing store is an engine source with `exists=false` and zero records. A registry that is not a regular database file, is not schema version 2, or does not have exactly one home row and 24-character lowercase hex keys exits 1 with `improve_source_unreadable`. Each store is opened read-only for one query over its events table and is never created, written, or migrated. Outside a KXM project only telemetry is read, and the text output says `Runtime store not read`. The example below is an unregistered checkout, so it lists one engine source.
|
|
3510
|
+
- A telemetry record whose `attemptId` an earlier source already supplied is dropped (`duplicatesDropped`). The same drop applies between the home store and a lane store: the first source wins. Attempts from simulated drives are excluded (`excludedSimulated`). Each Runtime attempt's outcome is resolved from the event log and never written back: `accepted` when the run completed and the step was not re-entered, `reworked` when the step was entered again, `failed` when the run failed, undecided (`undecided`) when the run was cancelled or is still running.
|
|
3511
3511
|
- A group becomes a candidate only when the same objective was decided in at least 2 runs, at least 0.75 of its decided records were accepted, and its step writes no repository. A group that passes but misses shows `no (writes-repository)` or `no (ask-not-repeated)`. `Weighted` is the recency-weighted record count (`improvement.telemetryHalfLifeDays`); it orders rows and never decides candidacy.
|
|
3512
3512
|
- Reads `improvement.*` from the project and user configuration (see [`kxm.config.v1`](config-reference.md#personalization-settings-kxmconfigv1)) and reports each candidate's promotion readiness under `improvement.promotionPolicy`. Readiness never authorizes anything. Under `critic_quorum` every candidate reports not ready, because this command cites no critic receipts. A configuration that cannot be loaded exits 1 with `config_invalid`.
|
|
3513
|
-
- A Runtime store that exists but cannot be read exits 1 with `improve_source_unreadable`; `detail` names the path.
|
|
3513
|
+
- A Runtime store or registry that exists but cannot be read, and a registry whose identity is corrupt, exits 1 with `improve_source_unreadable`; `detail` names the path.
|
|
3514
3514
|
- Writes candidate files under `--out-dir` (relative to the current directory) and the report at `.kxm/assets/improvements/<timestamp>.json`. Honors `--dry-run` (writes neither). No hub needed.
|
|
3515
3515
|
- JSON keys: `path`, `events`, `recordsCount`, `groupsCount`, `candidatesCount`, `candidates`, `report` (`schema`, `createdAt`, `reviewDecision`, `recordsCount`, `groups`, `candidates`, `promotionPolicy`, `promotion`, and `routeSwitches` when the store recorded any), `sources`, `projectRoot` (`null` outside a project). `routeSwitches` lists opted-in mid-attempt walks (`from`, `to`, `reason`, optional `effort`, `attemptId`, `stepId`). It is omitted when there are none.
|
|
3516
|
-
- Each `sources` entry has `kind` (`engine`, `telemetry`, or `file`), `path`, `exists`, `records`, and `duplicatesDropped`;
|
|
3516
|
+
- Each `sources` entry has `kind` (`engine`, `telemetry`, or `file`), `path`, `exists`, `records`, and `duplicatesDropped`; each `engine` entry also has `skippedInvalid`, `excludedSimulated`, and `undecided`. A registered project has one `engine` entry for the home store and one for each lane store.
|
|
3517
3517
|
- Each `report.groups` row has `workflowHash`, `workflowId` (Runtime records), `stepId`, `agentRole`, `promptHash`, `recurrence`, `distinctRuns`, `askRecurrence`, `undecidedRecords`, `meanCost`, `meanLatency`, `verifyPassRate` (accepted share of decided records), `rework`, `weightedRecurrence`, `undatedRecords`, `costSamples`, `writesRepository`, `evidenceRefs`, `isCandidate`, and, when they apply, `excludedReason`, `candidateKind`, and `candidateId`.
|
|
3518
3518
|
- Each `report.promotion` entry has `candidateId`, `policy`, `readyForReview`, and `reason`.
|
|
3519
3519
|
|
|
@@ -3565,18 +3565,18 @@ kxm routing report [-f <path>] [-l] [--prices <path>]
|
|
|
3565
3565
|
|
|
3566
3566
|
Compare verified completion, cost, and rework per behavioral configuration. The table ranks routes quality-first with columns Harness, Model, Effort, Role, Att, Pass%, Rwk%, p50(ms), p95(ms), CtxTok, Metered($), $/Acc, Unm, Unk, Quota, and optionally ListEquiv($).
|
|
3567
3567
|
|
|
3568
|
-
Without `--file` it reads the same sources as [`kxm improve report`](#kxm-improve-report): the
|
|
3568
|
+
Without `--file` it reads the same sources as [`kxm improve report`](#kxm-improve-report): the registered home store and every lane store for that project (read-only), or only this checkout's store when the registry is absent or this checkout is unregistered, then the workspace `telemetry.jsonl`, dropping a later copy of an attempt an earlier source already supplied and excluding simulated drives. A Runtime attempt counts toward Pass% only when the event log shows its run completed without the step being re-entered.
|
|
3569
3569
|
|
|
3570
3570
|
| Option | Argument | Default | Description |
|
|
3571
3571
|
|---|---|---|---|
|
|
3572
|
-
| `-f`, `--file` | `<path>` | the Runtime
|
|
3572
|
+
| `-f`, `--file` | `<path>` | the Runtime stores, then workspace telemetry | Read only this telemetry or event log JSONL file (default: this project's Runtime event stores plus workspace telemetry) |
|
|
3573
3573
|
| `-l`, `--equivalent-list-cost` | none | off | Include equivalent list price column using price catalog |
|
|
3574
3574
|
| `--list-prices` | none | off | Alias for --equivalent-list-cost |
|
|
3575
3575
|
| `--prices` | `<path>` | `.kxm/prices.yaml` | Path to price catalog (default: .kxm/prices.yaml) |
|
|
3576
3576
|
|
|
3577
3577
|
- Reads only. A price catalog that cannot be loaded is skipped silently.
|
|
3578
3578
|
- `--equivalent-list-cost` loads the catalog without the freshness check the producers apply, so it prices with a catalog of any date, including one the producers treat as stale. Check the catalog `date` before you rely on `ListEquiv($)`.
|
|
3579
|
-
- A Runtime store that exists but cannot be read exits 1 with `improve_source_unreadable`.
|
|
3579
|
+
- A Runtime store or registry that exists but cannot be read exits 1 with `improve_source_unreadable`. `--file` does not read the registry or any event store.
|
|
3580
3580
|
- Ranking: quality first (Pass%, then Rwk%), then cost per accepted attempt. Among routes of equal quality, any route with an unknown-cost attempt ranks after every route without one. Such a route's cost is unknown, not a partial sum: `$/Acc` prints `-` (JSON `costPerAcceptedUsd: null`) and the `*` in `Unk` marks it.
|
|
3581
3581
|
- The `Quota` column counts attempts whose metadata looks quota-exhausted (a quota failure class, a `quota` flag, or text such as `rate limit` or `HTTP 429`). It is a count only. Quota is not an `onError` class, and the column does not choose a route. Walks a role opted into are listed under Route switches when the store has `routing.route_switched` events (`from`, `to`, `reason`, optional `effort`, `stepId`).
|
|
3582
3582
|
- The text output does not list the sources, and prints `no routing records in telemetry` when no source holds a record. The Rwk% column counts records with `transitions` greater than 0, which Runtime records never set.
|
|
@@ -30,6 +30,7 @@ Names that start with `KXM_` are not all operator settings. This map covers ever
|
|
|
30
30
|
| Agents | `KXM_SERVER_URL`, `KXM_AUTH_TOKEN`, `KXM_PROJECT`, `KXM_AGENT_NAME`, `KXM_AGENT_PURPOSE` | [Agent settings](#agent-settings) |
|
|
31
31
|
| Long-lived Pi workers | `KXM_PI_COMMAND`, `KXM_WORKER_*` (operator settings), `KXM_AGENT_LOG_PATH` | [Long-lived worker settings](#long-lived-worker-settings) |
|
|
32
32
|
| Runtime supervisor | `KXM_STATE_HOME`, `KXM_RUNTIME_SYNC_INTERVAL_MS`, `KXM_RUNTIME_STOP_GRACE_MS` | [Runtime supervisor settings](#runtime-supervisor-settings) |
|
|
33
|
+
| Studio and Python control plane | `KXM_CONTROL_URL`, `KXM_KXMD_*`, `KXM_AUTHENTIK_*`, `KXM_POSTGRES_*`, `KXM_DATABASE`, `KXM_DB_USER`, `KXM_TEMPORAL_*` | [Studio and Python control-plane settings](#studio-and-python-control-plane-settings) |
|
|
33
34
|
| Operator CLI and sessions | `KXM_USER_CONFIG_DIR`, `KXM_USER_TELEMETRY_DIR`, `KXM_SESSION_TOKEN`, `KXM_SESSION_BRIEF`, `KXM_WORKFLOW_*`, `GITHUB_TOKEN`, and others | [CLI and session settings](#cli-and-session-settings) |
|
|
34
35
|
| Nous model providers | `KXM_NOUS_PROVIDERS`, `KXM_NOUS_PROXY_URL`, `KXM_NOUS_DISCOVERY_TIMEOUT_MS`, `KXM_NOUS_CATALOG_FILE`, `NOUS_API_KEY` | [Nous providers](../guides/nous-providers.md) |
|
|
35
36
|
| Browser automation | `KXM_BROWSER`, `OBSCURA_CDP_URL`, `OBSCURA_PORT`, `STEEL_API_URL`, `STEEL_UI_URL`, `STEEL_AUTH_HEADER`, `STEEL_AUTH_BASIC`, `STEEL_AUTH_USER`, `STEEL_AUTH_TOKEN`, `STEEL_API_KEY` (legacy), `USE_PASS_CLI` | [Browser settings](#browser-automation) |
|
|
@@ -187,6 +188,27 @@ The Runtime supervisor runs `kxm run` workflows and syncs their summaries to the
|
|
|
187
188
|
| `KXM_RUNTIME_SYNC_INTERVAL_MS` | `10000` | How often the supervisor heartbeats and pushes its outbox, clamped to `250` through `60000` |
|
|
188
189
|
| `KXM_RUNTIME_STOP_GRACE_MS` | `30000` | How long a stopping supervisor waits for open drives, `0` to `600000`; an invalid value warns and uses the default |
|
|
189
190
|
|
|
191
|
+
## Studio and Python control-plane settings
|
|
192
|
+
|
|
193
|
+
The MG1 Python service is additive: these values do not redirect the Node hub
|
|
194
|
+
or Runtime from SQLite. Requests cannot override its database host, database,
|
|
195
|
+
role, Temporal target, or namespace.
|
|
196
|
+
|
|
197
|
+
| Variable | Default | Effect |
|
|
198
|
+
|---|---|---|
|
|
199
|
+
| `KXM_CONTROL_URL` | Unset | Python control API base URL used by Studio's `GET /api/control/account` relay. The relay returns `control_unconfigured` when absent, and aborts a nonresponding upstream after three seconds with `control_unreachable` |
|
|
200
|
+
| `KXM_KXMD_PASSWORD` | None; required | PostgreSQL password for the fixed `kxmd` role. Keep it in the deployment secret manager |
|
|
201
|
+
| `KXM_POSTGRES_HOST` | `127.0.0.1` | PostgreSQL host selected by the service deployment, including an operator-owned tunnel |
|
|
202
|
+
| `KXM_POSTGRES_PORT` | `5432` | PostgreSQL port, from 1 through 65535 |
|
|
203
|
+
| `KXM_DATABASE` | `kxmd` | Fixed database assertion. Any other value refuses startup-time account resolution |
|
|
204
|
+
| `KXM_DB_USER` | `kxmd` | Fixed PostgreSQL role assertion. Any other value is refused |
|
|
205
|
+
| `KXM_TEMPORAL_TARGET` | `127.0.0.1:7233` | Temporal endpoint selected by the service deployment |
|
|
206
|
+
| `KXM_TEMPORAL_NAMESPACE` | `kxmd` | Fixed Temporal namespace assertion. Any other value is refused |
|
|
207
|
+
| `KXM_KXMD_ARTIFACTS` | `/var/lib/kxm/artifacts/kxmd` | Root for bounded per-tenant artifacts |
|
|
208
|
+
| `KXM_AUTHENTIK_ISSUER` | None; required for authenticated routes | Exact token issuer |
|
|
209
|
+
| `KXM_AUTHENTIK_AUDIENCE` | None; required for authenticated routes | Exact token audience |
|
|
210
|
+
| `KXM_AUTHENTIK_JWKS_URL` | None; required for authenticated routes | JWKS endpoint used to verify RS256 user and runner tokens |
|
|
211
|
+
|
|
190
212
|
## CLI and session settings
|
|
191
213
|
|
|
192
214
|
| Variable | Default | Effect |
|
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.182",
|
|
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",
|