@kontextmind/kxm 0.7.95 → 0.7.97

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.kxm/README.md +39 -9
  3. package/CHANGELOG.md +23 -1
  4. package/README.md +147 -257
  5. package/SECURITY.md +21 -12
  6. package/docs/README.md +133 -54
  7. package/docs/adr/ADR-0002-browser-automation-steel-doks.md +24 -18
  8. package/docs/adr/ADR-0003-sqlite-only-store.md +100 -0
  9. package/docs/adr/ADR-0004-edge-identity-authentik.md +99 -0
  10. package/docs/adr/README.md +33 -0
  11. package/docs/concepts/architecture.md +262 -0
  12. package/docs/concepts/data-and-storage.md +194 -0
  13. package/docs/concepts/trust-model.md +153 -0
  14. package/docs/contracts/README.md +22 -14
  15. package/docs/contracts/effects-and-recovery.md +3 -0
  16. package/docs/contracts/migration.md +2 -2
  17. package/docs/contracts/routing.md +6 -5
  18. package/docs/contributing/assignment-runner.md +388 -0
  19. package/docs/contributing/ci-and-release.md +231 -0
  20. package/docs/contributing/development.md +362 -0
  21. package/docs/contributing/harness-routing-internals.md +192 -0
  22. package/docs/{packages.md → contributing/packages.md} +13 -15
  23. package/docs/{skills → contributing}/repo-work-delivery.md +20 -21
  24. package/docs/contributing/test-matrix.md +208 -0
  25. package/docs/{tui-components.md → contributing/tui-components.md} +30 -22
  26. package/docs/contributing/writing-docs.md +340 -0
  27. package/docs/glossary.md +471 -0
  28. package/docs/guides/agent-skills.md +137 -0
  29. package/docs/guides/browser-automation.md +160 -0
  30. package/docs/guides/context-and-memory.md +352 -0
  31. package/docs/guides/continuous-improvement.md +228 -0
  32. package/docs/guides/governed-skills.md +173 -0
  33. package/docs/guides/nous-providers.md +186 -0
  34. package/docs/guides/peer-messaging.md +304 -0
  35. package/docs/guides/pi-workers.md +219 -0
  36. package/docs/guides/provenance-gates.md +313 -0
  37. package/docs/guides/webhook-workflows.md +399 -0
  38. package/docs/kb/how-credentials-retrieved-safely.md +38 -12
  39. package/docs/kb/how-to-capture-and-annotate-section.md +15 -13
  40. package/docs/kb/how-to-connect-playwright-to-steel.md +16 -11
  41. package/docs/kb/how-to-recover-expired-session-or-orphan.md +26 -16
  42. package/docs/kb/how-to-resume-after-mfa.md +19 -11
  43. package/docs/kb/how-to-take-over-session.md +17 -13
  44. package/docs/kb/why-authentication-disappeared.md +22 -14
  45. package/docs/kb/why-automation-opened-different-browser.md +23 -14
  46. package/docs/kb/why-session-viewer-cannot-control.md +13 -12
  47. package/docs/operations/backup-and-restore.md +248 -0
  48. package/docs/operations/deploy.md +307 -0
  49. package/docs/operations/monitoring.md +209 -0
  50. package/docs/operations/runtime-sync.md +192 -0
  51. package/docs/operations/troubleshooting.md +266 -0
  52. package/docs/operations/upgrade.md +124 -0
  53. package/docs/prompts/browser-annotate-feedback.md +7 -7
  54. package/docs/prompts/browser-diagnose-recover.md +11 -10
  55. package/docs/prompts/browser-explore.md +7 -7
  56. package/docs/prompts/browser-repro-fix.md +7 -7
  57. package/docs/prompts/browser-start.md +12 -11
  58. package/docs/prompts/browser-takeover.md +8 -8
  59. package/docs/{cli-reference.md → reference/cli-reference.md} +88 -46
  60. package/docs/{config-reference.md → reference/config-reference.md} +159 -148
  61. package/docs/reference/configuration.md +299 -0
  62. package/docs/reference/harness-routing.md +508 -0
  63. package/docs/reference/http-api.md +203 -0
  64. package/docs/reference/tools.md +370 -0
  65. package/docs/{workflow-guide.md → reference/workflow-catalog.md} +92 -153
  66. package/docs/reference/workflow-definitions.md +286 -0
  67. package/docs/start/first-workflow.md +287 -0
  68. package/docs/start/install.md +146 -0
  69. package/docs/start/quickstart-claude-code.md +405 -0
  70. package/docs/start/quickstart-pi.md +213 -0
  71. package/docs/templates/README.md +78 -73
  72. package/docs/templates/adr.md +13 -13
  73. package/docs/templates/architecture.md +55 -71
  74. package/docs/templates/bug-fix.md +13 -16
  75. package/docs/templates/feature.md +14 -19
  76. package/docs/templates/handoff.md +44 -46
  77. package/docs/templates/postmortem.md +30 -43
  78. package/docs/templates/research.md +15 -20
  79. package/docs/templates/review.md +49 -50
  80. package/docs/templates/runbook.md +38 -30
  81. package/docs/templates/test-plan.md +16 -23
  82. package/docs/templates/test-report.md +14 -17
  83. package/examples/README.md +9 -5
  84. package/examples/provenance-workflow.json +1 -1
  85. package/examples/webhook-workflows/jira-development.json +59 -0
  86. package/examples/webhook-workflows/jira-issue-updated.json +12 -0
  87. package/examples/workflow-signal.ts +4 -5
  88. package/package.json +1 -1
  89. package/packages/core/tui/README.md +1 -1
  90. package/plugins/kxm/.claude-plugin/plugin.json +1 -1
  91. package/plugins/kxm/README.md +31 -32
  92. package/plugins/kxm/dist/claude-hook.js +11 -1
  93. package/plugins/kxm/dist/cli.js +164 -79
  94. package/plugins/kxm/dist/client.js +3 -1
  95. package/plugins/kxm/dist/core.js +11 -1
  96. package/plugins/kxm/dist/extension.js +45 -13
  97. package/plugins/kxm/dist/mcp-server.js +20 -4
  98. package/plugins/kxm/dist/runtime-supervisor.js +1 -3
  99. package/plugins/kxm/dist/runtime.js +18 -4
  100. package/plugins/kxm/dist/server.js +115 -20
  101. package/plugins/kxm/package.json +1 -1
  102. package/plugins/kxm/skills/kxm/references/protocol.md +3 -1
  103. package/plugins/kxm/skills/kxm-browser-auth/SKILL.md +1 -1
  104. package/plugins/kxm/skills/kxm-browser-diagnostics/SKILL.md +5 -5
  105. package/plugins/kxm/skills/kxm-browser-explore/SKILL.md +2 -2
  106. package/plugins/kxm/skills/kxm-browser-session/SKILL.md +10 -13
  107. package/plugins/kxm/skills/kxm-browser-takeover/SKILL.md +1 -1
  108. package/plugins/kxm/skills/kxm-browser-verify/SKILL.md +1 -1
  109. package/plugins/kxm/skills/kxm-context-memory/SKILL.md +13 -4
  110. package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +3 -1
  111. package/plugins/kxm/skills/kxm-mind-setup/SKILL.md +2 -1
  112. package/plugins/kxm/skills/kxm-project-setup/SKILL.md +31 -54
  113. package/plugins/kxm/skills/kxm-projects/SKILL.md +1 -1
  114. package/plugins/kxm/skills/kxm-protocol/SKILL.md +1 -1
  115. package/plugins/kxm/skills/kxm-routing-improve/SKILL.md +15 -7
  116. package/plugins/kxm/skills/kxm-runs/SKILL.md +11 -5
  117. package/plugins/kxm/skills/kxm-session/SKILL.md +1 -1
  118. package/plugins/kxm/skills/kxm-tasks/SKILL.md +9 -7
  119. package/plugins/kxm/skills/kxm-workflow/SKILL.md +10 -2
  120. package/plugins/kxm/src/cli/system.ts +1 -1
  121. package/plugins/kxm/src/cli/workflows.ts +12 -7
  122. package/plugins/kxm/src/cli.ts +22 -8
  123. package/plugins/kxm/src/client.ts +4 -0
  124. package/plugins/kxm/src/commands.ts +23 -1
  125. package/plugins/kxm/src/extension.ts +20 -14
  126. package/plugins/kxm/src/github-watch.ts +8 -5
  127. package/plugins/kxm/src/hub-env.ts +19 -1
  128. package/plugins/kxm/src/hub.ts +105 -21
  129. package/plugins/kxm/src/improve-sources.ts +2 -7
  130. package/plugins/kxm/src/init-guide-setup.ts +1 -1
  131. package/plugins/kxm/src/mcp-server.ts +9 -2
  132. package/plugins/kxm/src/modes.ts +1 -1
  133. package/plugins/kxm/src/runtime-store.ts +23 -0
  134. package/plugins/kxm/src/workflow.ts +70 -1
  135. package/schemas/README.md +1 -1
  136. package/scripts/smoke-multi-pi.mjs +5 -1
  137. package/docs/agent-communication-envelopes-and-gates.md +0 -553
  138. package/docs/agent-skills.md +0 -198
  139. package/docs/architecture.md +0 -245
  140. package/docs/assignment-runner.md +0 -264
  141. package/docs/browser-automation.md +0 -139
  142. package/docs/configuration.md +0 -437
  143. package/docs/continuous-improvement.md +0 -226
  144. package/docs/getting-started.md +0 -277
  145. package/docs/harness-routing.md +0 -616
  146. package/docs/kb/qa-authentik-authentication.md +0 -97
  147. package/docs/kb/qa-extension-install-and-hub-bootstrap.md +0 -85
  148. package/docs/kb/qa-hub-on-a-public-host.md +0 -48
  149. package/docs/kb/qa-sqlite-vs-duckdb.md +0 -35
  150. package/docs/kb/qa-what-the-hub-stores.md +0 -64
  151. package/docs/kxm-handbook.md +0 -1181
  152. package/docs/operations.md +0 -510
  153. package/docs/operator-pi-packages.md +0 -67
  154. package/docs/provenance-gates.md +0 -295
  155. package/docs/skills.md +0 -47
  156. package/docs/test-matrix.md +0 -132
  157. package/docs/troubleshooting.md +0 -322
  158. package/docs/webhook-workflows.md +0 -240
@@ -1,510 +0,0 @@
1
- # Operations guide
2
-
3
- This guide covers the production envelope for one KXM hub and one SQLite database.
4
-
5
- ## Deployment classification
6
-
7
- Version `0.4.x` is designed for local workstations and controlled trusted-team hosts. It provides durable restart recovery, project authentication, signed webhook workflows, traffic limits, health signals, metrics, structured logs, and graceful shutdown.
8
-
9
- It is not a clustered or multi-tenant control plane. Run one writer for each database. Do not place a load balancer across independent hubs and expect shared presence or delivery.
10
-
11
- ## Start and stop
12
-
13
- ```powershell
14
- $env:KXM_HOST = "127.0.0.1"
15
- $env:KXM_AUTH_TOKEN = "replace-with-a-long-random-token"
16
- $env:KXM_WORKSPACE_DIR = "D:\work\product\.kxm"
17
- kxm hub start
18
- ```
19
-
20
- These operator commands assume the packed release CLI installation from
21
- [Getting started](getting-started.md#1-install). From a
22
- source clone, use `npm run hub` instead.
23
-
24
- When `KXM_AUTH_TOKEN` is not set, `kxm hub start` loads the persisted hub
25
- credential file (schema `kxm.hub-env.v1`) under the user state root
26
- (`~/.local/state/kxm/hub-env.json` on Linux, honoring `KXM_STATE_HOME` and
27
- platform equivalents). If no persisted token exists, a long random
28
- administrative token is generated, saved there with `0600` permissions, and
29
- used. The hub therefore never silently starts with `auth=none` because a
30
- token was forgotten; a missing token is created once and reused by every
31
- later restart, worker, and dashboard on the same machine. Explicit
32
- `KXM_AUTH_TOKEN` / `KXM_PROJECT_TOKENS` environment values always win and are
33
- persisted so restarts keep them. The generated value is never printed in
34
- full; kxm only reports which file it came from.
35
-
36
- Stop with `Ctrl+C` or `SIGTERM`. The hub stops accepting connections, closes SSE streams, waits for active HTTP connections, and closes SQLite.
37
-
38
- For unattended service, use a supervisor that sets a stable working directory, injects secrets, captures stdout, restarts after failure, and allows at least five seconds for graceful shutdown.
39
-
40
- ### PID claims and restart recovery
41
-
42
- The hub wrapper records its own PID and the server child PID in
43
- `.kxm/state/hub.pid`. A claim whose wrapper is dead is reclaimed automatically
44
- on the next `kxm hub start`; when the dead wrapper left an orphaned server
45
- child behind (for example after `SIGKILL` or a machine crash), the new
46
- wrapper terminates that orphan before reclaiming. `kxm hub stop` also
47
- recovers orphans directly: it signals a still-running recorded server child
48
- of a dead wrapper, waits for exit, and removes the stale claim. Malformed or
49
- foreign PID claims stay fail-closed; remove those only after verifying no
50
- hub process is running.
51
-
52
- Run each long-lived coordinator with `kxm agent worker --name <stable-name> --project <project> [--model <provider/model>] [--fallback-models <provider/model,...>] [--tools <name,...>]` under a separate service-manager unit. Use distinct worktrees for concurrent writers, explicit CPU and memory limits, and restart throttling outside the built-in bounded backoff. Enforce role ownership with the Pi tool allowlist: omit `bash`, `edit`, and `write` from read-only reviewers, even if their prompt also says not to edit. The worker launches Pi RPC mode and retains the most recent session unless configured otherwise. Use `--fresh-start` for a clean first session that may still resume after a later provider failure; reserve `--no-continue` for a worker that must never resume. For release verification, configure the [exact extension and skill sets](configuration.md#long-lived-worker-settings), including every required provider extension; configured categories disable discovery and fail closed on invalid paths. `kxm hub stop` writes a generation-matched control request; the worker asks Pi RPC to abort, waits for confirmation and state flush, and only force-stops the process tree after the bounded drain deadline. A final provider error leaves the inbound hub message delivered, gracefully restarts Pi, rotates to an unused fallback model, and preserves the session; Pi's own automatic retries always finish first. A tool that exceeds `KXM_WORKER_TOOL_TIMEOUT_MS` follows the same durable restart path without changing models. If `--continue` reports an invalid tool-result session, the worker retries once fresh, journals a redacted recovery envelope, and injects a bounded resume instruction for the durable run and stage. Do not copy `pi-agent-*.log` into journals or retrospectives.
53
-
54
- ### Workflow-specific Pi sessions
55
-
56
- Workflow isolation is opt-in during the upgrade-compatible release because the new scoped default directory cannot safely infer which pre-upgrade shared Pi session belonged to a worker. Enable it explicitly for coordinators and peers that may receive durable workflow work:
57
-
58
- ```powershell
59
- kxm agent worker --name coordinator --project product --session-isolation workflow
60
- ```
61
-
62
- Ordinary peer and operator messages reuse the worker's stable `default` Pi history. Each canonical workflow run uses `.kxm/state/pi-sessions/<workerKey>/runs/<runId>/`; only one Pi RPC child exists at a time. A route-change lifecycle event (`worker_session_routed`) is expected and does not consume restart budget or apply crash backoff. `worker_session_evicted` records bounded LRU cleanup. `worker_session_state_recovered` means a malformed binding manifest was quarantined and routing restarted safely at `default`; inspect the protected `.corrupt-*` file and workflow journal before deleting it. `worker_session_request_rejected` indicates a stale, malformed, mismatched-generation, or mismatched-source request and should be investigated if it repeats.
63
-
64
- Back up workflow model histories only if local Pi context is part of your recovery policy; authoritative workflow stages, evidence, and decisions remain in `kxm.db`, assets, and Git. Never use a Pi JSONL as the sole system of record. The first isolated launch starts fresh scoped storage; the previous shared Pi history remains available only in `off` mode and is not copied because a shared directory may contain several agents' sessions. To disable isolation temporarily, stop the exact worker cleanly and restart it with `--session-isolation off`; do not run isolated and shared supervisors concurrently under the same agent identity. Returning to `workflow` resumes the binding recorded in the manifest, subject to the configured retention bound.
65
-
66
- For GitHub-backed waits, run `kxm gate github watch` as a separate command. The hub does not poll GitHub. Success, failure, cancellation, and timeout produce the exact signed signal for the waiting run/stage/key; timeout exits `4` after posting `failed`.
67
-
68
- ## Live observer dashboard
69
-
70
- Run the read-only dashboard against the active workspace:
71
-
72
- ```powershell
73
- kxm --workspace D:\work\product\.kxm dash
74
- ```
75
-
76
- The dashboard uses Pi's `@earendil-works/pi-tui` renderer. With the administrative `KXM_AUTH_TOKEN`, it subscribes to `/v1/ops/events` and refreshes the project-scoped `/v1/ops/snapshot` on each SSE wakeup, keeping agent, open-message, and workflow metadata live without timer polling. Both endpoints omit request/reply bodies. Local process claims remain a local read-only snapshot. If the operations endpoints are unavailable or the supplied credential is project-scoped rather than administrative, the dashboard requests a hub-enforced presence-only agent SSE stream plus local SQLite metadata. It refuses an older/unmarked stream that cannot guarantee this metadata-only mode. Observer registrations are excluded from the dashboard's displayed agent table and counts; they remain ordinary authenticated hub identities while connected.
77
-
78
- | Key | Action |
79
- |---|---|
80
- | `1`–`6` | Agents, Tasks, Workflows, Plans, Inbox, or Procs |
81
- | `Tab` / `]` | Next tab |
82
- | `[` | Previous tab |
83
- | `←` / `→` | List pane / detail pane |
84
- | `↑` / `↓` | Select |
85
- | `PgUp` / `PgDn` | Scroll |
86
- | `h` | Toggle help |
87
- | `q` | Quit |
88
-
89
- In a non-interactive shell, `kxm dash` prints one ANSI-free snapshot and exits.
90
- Use `kxm hub view --json` instead when a machine-readable result is required.
91
-
92
- ## Real multi-Pi release smoke
93
-
94
- The opt-in release smoke requires two distinct models that already pass `pi auth check`. Both run as long-lived Pi workers, so both must pass the native-vendor brake: a model whose vendor has its own harness (for example `xai/…` or `anthropic/…`) is refused before Pi starts. It creates a temporary workspace, launches two real Pi RPC workers, and verifies discovery, request/reply, fanout, durable identity plus a post-restart exchange, journal persistence, checkpoint completion, and cleanup.
95
-
96
- PowerShell:
97
-
98
- ```powershell
99
- $env:KXM_SMOKE = "1"
100
- $env:KXM_SMOKE_MODELS = "openrouter/qwen/qwen3-coder-plus,openrouter/z-ai/glm-5.3-flash"
101
- node scripts/smoke-multi-pi.mjs
102
- ```
103
-
104
- POSIX shell:
105
-
106
- ```bash
107
- KXM_SMOKE=1 KXM_SMOKE_MODELS='openrouter/qwen/qwen3-coder-plus,openrouter/z-ai/glm-5.3-flash' node scripts/smoke-multi-pi.mjs
108
- ```
109
-
110
- For GitHub Actions, smoke runs on the ARC scale set `kontextmind-doks`. Set
111
- the GitHub repository variable `KXM_SMOKE_RUNNER` (a readiness latch, not a
112
- process environment variable) exactly to `kontextmind-doks` and
113
- `KXM_SMOKE_MODELS` to the two model IDs. Any other value skips the job. A
114
- manual dispatch can override the model variable with its `models` input.
115
- Readiness means Pi credentials are provisioned to ephemeral ARC pods and
116
- pass `pi auth check`, not general CI readiness. Credentials are never
117
- workflow inputs. The variable is currently unset, so the workflow is
118
- intentionally disabled.
119
-
120
- ## Health, readiness, and metrics
121
-
122
- | Endpoint | Authentication | Meaning |
123
- |---|---|---|
124
- | `GET /health` | None | Process is accepting HTTP and reports online agents |
125
- | `GET /ready` | None | Storage responds and the hub is ready for traffic |
126
- | `GET /metrics` | Administrative token outside loopback | Prometheus text metrics |
127
- | `GET /v1/ops/snapshot?project=<name>` | Administrative token | Project-scoped agent, open-message, and workflow metadata; no bodies |
128
- | `GET /v1/ops/events?project=<name>` | Administrative token | Metadata-only SSE wakeups for live dashboard refresh |
129
-
130
- Use `/ready` for service traffic and `/health` for liveness. Metrics include online agents, retained messages, requests, errors, registrations, sends, replies, cancellations, expiries, purges, workflow waits, external signals, wait timeouts, and explicit workflow quorum degradations.
131
-
132
- Structured JSON logs are written to `.kxm/logs/kxm-hub.jsonl` and mirrored to stdout. They include request IDs and event metadata but omit prompt and reply bodies. Worker lifecycle events use `.kxm/logs/kxm-worker-<project>-<agent>-<identity>.jsonl`; raw headless Pi stdout and stderr use `.kxm/logs/pi-agent-<project>-<agent>-<identity>.log` and may contain sensitive model or tool output. The collision-resistant suffix separates exact project/agent owners even when display names sanitize identically. Useful hub events include `agent_registered`, `agent_resumed`, `agent_stale`, `message_sent`, `message_replied`, `message_cancelled`, `message_expired`, `message_purged`, `webhook_workflow_started`, `workflow_checkpoint`, `workflow_degradation_approved`, `workflow_wait_started`, `workflow_signal_received`, `workflow_wait_timed_out`, `workflow_journal_recorded`, and `request_error`.
133
-
134
- Runtime logs are ignored by Git. Ship them to an approved collector, restrict file access, and apply retention or rotation outside the process before unattended use. Never commit them as workflow evidence; reference a protected log location or sanitized asset instead.
135
-
136
- Recommended alerts:
137
-
138
- - readiness fails for more than one minute;
139
- - errors or rate-limit responses rise unexpectedly;
140
- - the process restarts repeatedly;
141
- - retained-message count grows despite the retention policy;
142
- - free disk space approaches the database's expected growth margin.
143
- - webhook signature rejections, repeated provider retries, premature workflow settlement, or attempt exhaustion increase.
144
- - waiting-run count or workflow wait timeouts rise beyond the expected external-system latency.
145
- - quorum degradation approvals occur outside a declared incident or change window.
146
-
147
- ## Per-tenant hosted deployment
148
-
149
- One tenant is one machine: one hub process, one Runtime supervisor, one SQLite state set.
150
- Tenancy is the box, not a table — the hub has no tenant column and no user accounts, and
151
- `kxm hub bind` still means *this machine's client attaches to that hub URL*. The portal
152
- (kontextmind/kxmd-portal) is the multi-tenant, multi-user surface; browsers never talk to
153
- the hub.
154
-
155
- Topology on the tenant box:
156
-
157
- ```text
158
- browser ──HTTPS──▶ reverse proxy + Authentik ──▶ portal (users, sessions, tenant directory)
159
- │
160
- │ server-side, loopback
161
- ▼
162
- hub 127.0.0.1:7331 · Runtime supervisor (loopback)
163
- ```
164
-
165
- 1. **Service account, not root.** Run the hub and Runtime under a dedicated unprivileged
166
- account. Workflow session isolation is a routing and cross-run safety mechanism, not a
167
- sandbox against a hostile same-OS process (see
168
- [architecture.md](architecture.md)); a model with shell access can reach anything its
169
- own account can reach, so untrusted workers need separate accounts or containers.
170
- 2. **Stable paths, declared explicitly** rather than inherited from a home directory:
171
- `KXM_WORKSPACE_DIR`, `KXM_STATE_DIR`, `KXM_DATA_PATH`, `KXM_LOG_PATH`, and
172
- `KXM_STATE_HOME` for the machine-level hub credential and binding records. Pin
173
- `KXM_HOST=127.0.0.1`.
174
- 3. **Loopback listeners only.** The hub and the supervisor expose no public port; nothing
175
- is load-balanced across hubs. The hub keeps one writer per database.
176
- 4. **One project, the slim workflow.** `kxm init` the workspace, then start the hub with
177
- `kxm hub start` and confirm with `kxm hub view` — the status line reports the binding as
178
- `loopback` or `remote`, so an operator can see which side of the trust line they are on
179
- without reading files. `kxm hub bind` refuses a **remote** URL when the machine has no
180
- credential to authenticate with, because a stored-but-unusable URL later reads as a
181
- network fault and gets debugged as one.
182
- 5. **Restart recovery is the existing one:** the PID claim file, dead-claim reclaim and
183
- graceful `SIGTERM` shutdown described under *PID claims and restart recovery*. Do not
184
- add a second service manager for the hub; use the tenant's existing one.
185
-
186
- ### Reverse-proxy contract
187
-
188
- The tenant's proxy owns TLS and the browser session. KXM ships no proxy configuration,
189
- because a generated config reads as authoritative while one missing directive silently
190
- re-opens header forgery. What must hold, whatever the stack:
191
-
192
- - The hub and supervisor ports are **not** reachable from outside the box.
193
- - The proxy **strips** client-supplied identity, tenant, agent, caller and `Authorization`
194
- headers before injecting its own validated values. The hub must never see a
195
- browser-forged `x-kxm-agent-id`, `x-kxm-caller-id` or bearer.
196
- - The proxy **never injects the hub admin token on a user's behalf**. That flattens every
197
- authenticated user in the tenant to hub admin and destroys attribution.
198
- - Machine credentials stay server-side in the portal process. A browser must not hold,
199
- echo, or be redirected with a hub bearer.
200
- - `kxm hub bind` on a remote hub URL therefore requires an explicit credential, and a
201
- refusal names the fix instead of only the failure.
202
-
203
- Example (illustrative shape — not generated config, not tested by this repository's CI):
204
- Authentik's embedded proxy answers a forward-auth subrequest per request; the tenant proxy
205
- `proxy_cache_bypass`/`auth_request`-style gate allows only the portal's routes and keeps
206
- `/v1/*` and the supervisor off the public interface entirely.
207
-
208
- ## Backup and restore
209
-
210
- > **This section covers the whole tenant state set, on purpose.** A recipe that copies only
211
- > `.kxm/state/kxm.db` is a hub-only backup: it silently omits the Runtime registry,
212
- > per-project event stores, prompt sidecars, bindings and configuration, so a restore that
213
- > passes every hub check can still lose run history. Verify with a real restore before first
214
- > hosted use, not after an incident.
215
-
216
- SQLite runs in WAL mode, so a consistent copy requires a stopped service (or a SQLite-aware
217
- online tool). Stop the hub and the Runtime supervisor first.
218
-
219
- **What a tenant backup contains.** Six roots — one fixed to the checkout, one for the
220
- workspace directories, and four more that can each sit anywhere — and confusing them is how
221
- a backup goes missing while looking complete:
222
-
223
- - **`$S`** — host-local machine state: `$KXM_STATE_HOME` **when set**, and it must be an
224
- absolute path — a relative value is **rejected** with `local_state_root_not_absolute`, not
225
- redirected. When unset, the default is `~/.local/state/kxm` on Linux (honouring
226
- `XDG_STATE_HOME`), `~/Library/Application Support/KXM` on macOS, or
227
- `%LOCALAPPDATA%\KXM` on Windows. The silent case to know about is a relative
228
- `XDG_STATE_HOME`/`LOCALAPPDATA` **base**: that falls back to the default without error,
229
- so a backup path derived from it can quietly point somewhere else.
230
- - **`$R`** — the checkout root. Everything below it is **fixed to the repository and does
231
- not follow any workspace override**: `$R/.kxm/project.yaml`, `$R/.kxm/config.yaml`,
232
- `$R/.kxm/agents/`, `$R/.kxm/workflows/`, `$R/.kxm/gates.yaml`, `$R/.kxm/roles/`,
233
- `$R/.kxm/role-hosts.yaml` (or `.json`), `$R/.kxm/producers.yaml`, `$R/.kxm/roster.yaml`,
234
- `$R/.kxm/routes.yaml`, `$R/.kxm/prices.yaml`, `$R/.kxm/repo/`,
235
- `$R/.kxm/template-provenance.yaml`, plus the durable work and learning records
236
- `$R/.kxm/goals/`, `$R/.kxm/tasks/`, `$R/.kxm/memory/` (with `memory/candidates/`) and
237
- `$R/.kxm/skills/`. Conflating these with the next root is how a backup omits the project
238
- definition while believing it copied the project.
239
- - **`$D`** — the **workspace directories**, resolved from `--workspace` or
240
- `KXM_WORKSPACE_DIR`, else `$R/.kxm`, relative to `KXM_WORKDIR`/cwd:
241
- `$D/config`, `$D/logs`, `$D/assets`, `$D/state`. `--workspace` **derives all four** and
242
- ignores the per-directory variables; otherwise `KXM_CONFIG_DIR`, `KXM_LOGS_DIR`,
243
- `KXM_ASSETS_DIR` and `KXM_STATE_DIR` override each one independently, and
244
- `KXM_DATA_PATH`/`KXM_LOG_PATH` move two files again inside that. `$D` therefore **defaults to `$R/.kxm`**, and the two
245
- move together only when the *workspace* is relocated: `KXM_WORKSPACE_DIR` (or
246
- `--workspace`) moves `$D` and every default beneath it, while `KXM_CONFIG_DIR`,
247
- `KXM_LOGS_DIR`, `KXM_ASSETS_DIR`, `KXM_STATE_DIR`, `KXM_DATA_PATH` and `KXM_LOG_PATH`
248
- move **their own target and nothing else** — `KXM_STATE_DIR=/srv/state` alone leaves `$D`
249
- at `$R/.kxm` and shifts only `$W`. A backup that assumes one shared location starts
250
- omitting the other in exactly that case, which is why every row below is labelled as a
251
- default.
252
- - **`$W`** — the workspace *state* directory: `KXM_STATE_DIR` when set, else `$D/state`
253
- (and `--workspace` derives it, ignoring that variable). It holds the
254
- hub database, worker routing/recovery manifests and Pi sessions.
255
- - **`$C`** — user configuration: `KXM_USER_CONFIG_DIR`, else `~/.config/kxm`.
256
- - **`$T`** — federated telemetry output: an explicit global directory joined with
257
- **`telemetry/`**, else `$XDG_CONFIG_HOME/kxm/telemetry`, else `~/.config/kxm/telemetry`.
258
- It is built from `XDG_CONFIG_HOME`/`HOME`, **not** from `KXM_USER_CONFIG_DIR`, so `$T` can
259
- land outside `$C`; and it is a *different file* from local accounting in `$D/logs`.
260
-
261
- | Path | Contents | Loss means |
262
- |---|---|---|
263
- | `$W/kxm.db` (+ `-wal`, `-shm`, or `KXM_DATA_PATH`) | hub store: agents, messages, workflow runs, checkpoints, gate evidence | hub history and delivery state |
264
- | `$S/runtime/registry.db` | Runtime registry, including the **supervisor identity and claim row** | which projects this Runtime knows; the claim is a registry row — there is no `supervisor.json` |
265
- | `$S/runtime/projects/<projectKey>/run-events.db` (+ `-wal`/`-shm`) | event-sourced run state, commands, drives, receipts, gate evidence, intake, coordinators, pause control | run history and every receipt that proves it |
266
- | `$S/runtime/projects/<projectKey>/run-events.db.run-prompts.json` | prompt text; the sidecar name appends to the **full** database filename | the prompts that explain the runs — restoring databases without sidecars is a partial restore |
267
- | `$S/runtime/logs/kxm-runtime.jsonl` (+ rotated `.1`…) | the Runtime supervisor's own structured log, including every outbound-sync state change | the supervisor runs detached with no stdio: this file and `GET /v1/sync/status` are its only voice |
268
- | `$S/projects/<control-root-hash>/repository-bindings.json` | host-local member repository paths | member bindings are host state, outside the project tree |
269
- | `$S/update.yaml` | release/update configuration consumed by the updater | the box reverts to defaults on the next update path |
270
- | `$W/pi-sessions/<workerKey>/{default,runs/<runId>}/` | Pi model histories | **optional by existing policy** (see *Workflow-specific Pi sessions*): never a system of record — decide and record, do not silently widen scope |
271
- | `$W/worker-session-binding-<workerKey>.json` (+ `.corrupt-*`), `worker-context-*.json`, `worker-recovery-*.json` | routing and recovery manifests | not optional: these are what make worker routing resumable after a restart |
272
- | `$R/.kxm/…` project definition: `project.yaml`, `config.yaml`, `agents/`, `models/`, `workflows/`, `gates.yaml`, `roles/`, `role-hosts.yaml` (or `.json`), `producers.yaml`, `roster.yaml`, `routes.yaml`, `prices.yaml`, `repo/`, `project/env.yaml`, `template-provenance.yaml` | project, role, route, price and provenance definition | the tenant stops being reproducible — and a restore without `roster.yaml`/`routes.yaml`/`prices.yaml` comes back with **different admission and cost behaviour** while reporting itself healthy |
273
- | `$R/.kxm/goals/`, `tasks/`, `memory/` (with `memory/candidates/`), `skills/` (candidate/promoted/rejected, history, patches) | durable work and learning records | open goals/tasks and approved memory disappear |
274
- | `$R/.kxm/candidates/` — improvement candidate JSON and their diffs, **default only**: `kxm improve report --out-dir` relocates this directory outside every root listed here | the improvement queue itself | proposed fixes nobody was told about |
275
- | each bound member repository's own `$memberRepo/.kxm/repo/repo.yaml` and `.kxm/repo/env.yaml` | member repository definition and environment | for **externally bound** members, the binding JSON alone is not enough — these files live on the member's own filesystem and need their own backup or an explicit, checked reconstruction prerequisite |
276
- | `$D/assets/` (default; `KXM_ASSETS_DIR` relocates it) — retrospectives, improvements, artifacts, evidence | exported evidence | provenance and the ability to audit a past decision |
277
- | `$D/logs/` (default; `KXM_LOGS_DIR` relocates the directory and `KXM_LOG_PATH` the hub log) and `$D/logs/telemetry.jsonl` | operator logs and **local** usage accounting — the spend numbers routing reports read | no local accounting to reconcile against |
278
- | `KXM_WORKER_LOG_PATH` / `KXM_AGENT_LOG_PATH` targets (defaulting under `$D/logs`) | per-worker lifecycle and raw Pi output | worker diagnostics; **separate overrides, not local accounting** |
279
- | `$T/model-metrics.jsonl` | **federated** metrics only. Absent almost everywhere: the exporter exists and `telemetry.federated` defaults to `true` in the shipped config, but **no hub or CLI path calls it today**, so absence is the normal state rather than evidence someone opted out. A different file from local accounting, which is `$D/logs/telemetry.jsonl` | cross-machine reporting continuity, and a privacy boundary worth naming: federated records are separate, with `anonymize` defaulting to `true` |
280
- | `$S/hub-binding.json`, `$S/hub-env.json`, `$C/session.token` | host hub URL, credentials, local session token | a re-bind and a token rotation. **Secrets:** prefer regeneration to shipping them off-box, and never commit them |
281
- | `$C` global roles/workflows/host configuration | user-level defaults | operator conventions |
282
-
283
- **Overrides are part of the backup record.** `KXM_WORKSPACE_DIR` (and the `--workspace`
284
- flag, which additionally **ignores** the per-directory variables) moves every `$D`
285
- **default** at once; a directory with its own override stays where that variable points.
286
- Neither moves `$R`, so the fixed project tree must still be backed up from the checkout even
287
- when the workspace was relocated elsewhere — and copying the whole checkout is what protects
288
- `$R`'s default locations, which is why an enumerated-paths backup should be re-checked
289
- against this table whenever a loader grows a file. `KXM_STATE_HOME` moves `$S`
290
- only if absolute. An explicit telemetry directory is likewise joined with `telemetry/`,
291
- not used verbatim.
292
- `KXM_DATA_PATH`, `KXM_STATE_DIR`, `KXM_CONFIG_DIR`, `KXM_ASSETS_DIR`, `KXM_LOGS_DIR`,
293
- `KXM_LOG_PATH`, `KXM_WORKER_LOG_PATH`, `KXM_AGENT_LOG_PATH` or an explicit telemetry
294
- directory each relocate one more thing. Record every override **with** the backup, or a
295
- restore lands somewhere the running service will not look.
296
-
297
- **Disposable, not backup material:** `session-brief.json`, `update-check.json`,
298
- `*.error`, PID/claim files such as `hub.pid` and `worker-<key>.pid`, and
299
- `supervisor.token` (host-local secret, re-generated on start). WAL-consistent copying or
300
- `VACUUM INTO` applies to **every** SQLite file above, not only the hub database.
301
-
302
- **Back up (stopped-state recipe):**
303
-
304
- 1. Stop **both** services, confirm they are down, and **keep them down until the copy
305
- finishes**. `kxm hub stop` covers the hub and its worker PID claims; the Runtime
306
- supervisor is a **separate** process owning `registry.db` and the project event stores,
307
- stopped by `kxm runtime stop` — and that call acknowledges shutdown *initiated*, not
308
- databases closed. So: verify neither reports live, then suspend whatever would start them
309
- again — the service manager's auto-restart, hub autostart on login, and any client that
310
- would reconnect and begin new work (a bound CLI, MCP server or Pi worker restarting a
311
- supervisor on demand). A manager that respawns the hub halfway through a copy produces a
312
- backup that is internally inconsistent across files, which is precisely the failure mode
313
- this recipe is otherwise careful about. Only then copy.
314
- 2. Copy the whole set above as one tree — **every root**, `$R`, `$D`, `$W`, `$S`, `$C` and
315
- `$T` — or take `VACUUM INTO` snapshots per database. **Snapshots replace the database
316
- copies, not the file copy**: configuration, repository bindings, prompt sidecars,
317
- routing manifests and update configuration are not databases, so a snapshot-only backup
318
- reproduces exactly the failure this section exists to remove. The hub's own backup path already writes a hashed manifest and records
319
- a schema version ceiling; keep that manifest with the files. That ceiling is
320
- **hub store v5 and event store v6** as of the sync-outbox release: a backup taken by
321
- an earlier build records hub v4 or event store v5 and is refused by this one, because
322
- there is no migration lane.
323
- Restore such a backup with the release that produced it, or start fresh.
324
- 3. Record the package version, configuration revision and schema versions beside the copy.
325
- A restore that cannot state which release produced it is not a restore path.
326
- 4. Keep at least one rotation, and bound retention explicitly — run events and prompt
327
- sidecars grow, and unbounded retention is how a tenant box fills up.
328
-
329
- **Restore:**
330
-
331
- 1. Stop the services. Move the current state aside rather than overwriting it.
332
- 2. Place each file back at its recorded path under the right root — `KXM_DATA_PATH`, the
333
- Runtime registry and each project event store **with its sidecar**, repository bindings
334
- under `$S/projects/…`, config, and `$S/runtime/registry.db` so the supervisor claim
335
- returns with it.
336
- 3. Start the hub and confirm `/ready`, then `kxm hub view` — including that the reported
337
- binding scope is what the environment actually is.
338
- 4. Read back a run and its drive receipt, and confirm prompt text is present. Restoring
339
- databases without their sidecars leaves runs whose prompts are gone; that is a partial
340
- restore, not a success.
341
-
342
- The runtime refuses a database whose schema version is newer than it supports, so
343
- restore order is: matching-or-newer release, then data. Online backups need a
344
- SQLite-aware tool or a consistent snapshot of each database with its `-wal` and `-shm`;
345
- a plain copy of a live `kxm.db` can omit committed WAL data.
346
-
347
- Test restoration periodically. Routine unattended recovery (automated discovery of every
348
- Runtime store plus sidecars) is deliberately **not** claimed here: it is a tracked
349
- post-MVP item, and today this procedure is executed stopped and by hand.
350
-
351
- ## Upgrade and rollback
352
-
353
- 1. Back up the database and record the current package version.
354
- 2. Run `npm ci` for the target checkout.
355
- 3. Stop the old hub gracefully.
356
- 4. Start the new version against the database and verify `/ready`, `/metrics`, and a test round trip.
357
- 5. Restart agents only if their clients do not reconnect automatically.
358
-
359
- For rollback, stop the new version and restore both the earlier application and its pre-upgrade database backup. Do not open a newer-schema database with an older runtime.
360
-
361
- Peer provenance fields do not bump the current SQLite schema version 2; they are
362
- additive fields in existing JSON records. That avoids a destructive migration,
363
- but it does not replace the backup and rollback steps above. Verified
364
- metadata-only snapshots remain in workflow runs after their source messages are
365
- purged by terminal retention, so include workflow data in retention and privacy
366
- reviews.
367
-
368
- ## Network and secret security
369
-
370
- Loopback is the safest default. Before binding elsewhere, configure an administrative token, assign project tokens, terminate TLS at a trusted proxy, restrict inbound networks, disable proxy buffering for `/v1/events`, and protect the SQLite directory.
371
-
372
- The database is not encrypted by the application. Use encrypted storage when messages require encryption at rest. Rotate a disclosed token and reconnect affected agents. Never expose the hub directly to the public internet.
373
-
374
- ## Capacity and failure behavior
375
-
376
- The service uses one Node.js process, long-lived SSE connections, and one SQLite writer. Measure concurrent agents, request rate, event-loop delay, database size, disk latency, and reconnect frequency for your workload. The in-memory rate-limit ledger resets after process restart.
377
-
378
- | Failure | Behavior | Recovery |
379
- |---|---|---|
380
- | Agent exits | Marked offline after the stale threshold | Restart with the same name to resume its ID |
381
- | SSE drops | Client reconnects while heartbeats continue | Check network and proxy buffering if repeated |
382
- | Hub or worker exits | SQLite keeps agents and messages; session binding manifests keep the active Pi scope | Restart; agents reconnect and queued or delivered work replays by the same message ID in the bound Pi session |
383
- | Token rotates | Requests fail authentication | Restart agents with the new project token |
384
- | Disk unavailable | Readiness or writes fail | Restore storage, then verify database integrity and readiness |
385
- | Duplicate live name | Registration returns HTTP 409 | Stop the old session or choose another name |
386
- | External callback is lost | Run stays `waiting` until its deadline | Retry with the same delivery ID or investigate the provider before timeout |
387
- | External wait expires | Run and active stage fail; journal records the timeout and the coordinator receives a terminal notification | Fix delivery/routing, review side effects, then start a new safe workflow delivery |
388
- | Pi executable cannot spawn | Worker records the process error and applies its normal restart/backoff limit | Repair `PATH` or `KXM_PI_COMMAND`; confirm the worker exits nonzero when retries are exhausted |
389
- | Session binding manifest is corrupt | Worker quarantines it and starts the stable default binding without trusting a guessed run | Inspect `worker_session_state_recovered`, the `.corrupt-*` manifest, `kxm.db`, and workflow journal; re-drive unfinished work from durable message IDs |
390
- | Session route request is rejected | Candidate remains queued; wrong-scope acknowledgement never occurs | Check worker generation, active scope, canonical run ID, state-directory permissions, and repeated `worker_session_request_rejected` logs |
391
-
392
- Durable transport does not make peer execution exactly once. Use idempotent tasks and stable message idempotency keys, and store important artifacts in Git or another system of record.
393
-
394
- ## Remaining scale boundaries
395
-
396
- Broader deployments need shared state and coordination, external identity and fine-grained authorization, distributed traffic controls, defined service-level objectives, load and chaos testing, and a formal long-term schema migration strategy.
397
-
398
- ## v0.5 context/state storage
399
-
400
- The hub database (schema version 5) carries `context_items`, `leases`,
401
- `sync_events` and `runtime_presence` alongside agents, messages, workflow runs,
402
- and the journal. Temporal state,
403
- knowledge records, and their audit trails live in the same SQLite file and
404
- upgrade in place from v0.4 databases.
405
-
406
- - **Backup and restore**: include the hub database file and, if used, the
407
- `.kxm/skills/` and `.kxm/knowledge/` trees. The wiki is a compiled view and
408
- can be regenerated (`kxm context wiki-compile`); skills history and state
409
- records are authoritative and must be backed up.
410
- - **Recovery after restart**: runs, journal entries, transitions, captured
411
- oracles, and plan hashes reload from SQLite; temporal `asOf` queries are
412
- deterministic against the restored validity windows.
413
- - **Project isolation**: context/state/skill operations are project-scoped.
414
- Agents authenticate to their own project; administrative operations require
415
- the hub token. Cross-project context requests fail closed
416
- (`context_isolation_violation`).
417
- - **Rollback**: schema downgrades are not supported (a newer database refuses
418
- to open on an older runtime). Restore a database backup taken before the
419
- upgrade instead.
420
-
421
- ### Fenced leases over shared resources
422
-
423
- `leases` holds one row per project-scoped resource: the holder, a monotonic
424
- fencing token, and a deadline. `POST /v1/leases/:resource/acquire|renew|release`
425
- are agent-authenticated and scoped to the caller's project, which the hub
426
- prefixes onto the resource name — two projects naming the same branch never
427
- contend. TTLs are bounded to 5 s–10 min and every decision is made on the **hub
428
- clock** inside one store transaction, so a skewed client cannot extend its own
429
- grip.
430
-
431
- The token is the safety property. It starts at 1, stays put across renewals, and
432
- increments only when a new holder takes over an expired lease. A holder that
433
- comes back after its deadline is therefore told its token was superseded rather
434
- than allowed to write behind whoever replaced it. Shared external effects
435
- (`git-push` to a ref the run does not own, `pr-create`, `tracker-issue`,
436
- `webhook`) take a lease before executing and re-present the token at commit; a
437
- superseded token leaves the effect `in-flight` and the attempt
438
- `blocked_uncertain` for an operator to resolve, and nothing retries it. An
439
- unreachable hub refuses the effect (`effect_lease_unavailable`) rather than
440
- running it unfenced.
441
-
442
- Expired rows are **not** reaped immediately — their token is what the next
443
- takeover has to increment past. The retention sweep drops rows whose deadline is
444
- older than the run-retention window (7 days by default), far beyond any live
445
- holder. `kxm_leases_granted_total`, `kxm_leases_refused_total` and
446
- `kxm_leases_released_total` in `/metrics` report contention;
447
- `lease_acquired`, `lease_renewed`, `lease_released`, `lease_denied` and
448
- `lease_purged` are the structured log events.
449
-
450
- ### Runtime → hub run-fact sync
451
-
452
- Every event the Runtime commits also writes one row to the event store's
453
- `outbox` (event store v7), in the same transaction. The row holds only a derived
454
- `kxm.sync-event.v1` object — allowlisted fields, registered secret values and
455
- credential shapes replaced, absolute paths removed, text bounded, the default
456
- sync policy revision recorded — never the local event. A field the allowlist
457
- does not name is listed by name in `redaction.fieldsOmitted` and its value is
458
- dropped.
459
-
460
- The supervisor pushes outbound only: every `KXM_RUNTIME_SYNC_INTERVAL_MS` (10 s
461
- by default) it posts `POST /v1/runtime/presence` for each open project, then
462
- `POST /v1/sync/events` in outbox order, to `KXM_SERVER_URL` or the `kxm hub bind`
463
- URL with that project's token. No bound hub means nothing is sent and rows stay
464
- pending; local execution never waits on sync. The hub accepts each event once by
465
- `{projectId, runId, sequence}`: the same bytes again are an idempotent
466
- `duplicate`; different bytes under a used sequence, a run claimed by another
467
- project, or a push for another Runtime's events are refused and logged as
468
- `security_alert`. Out-of-order events are held, and the per-run cursor is the
469
- gapless prefix, so a gap stays pending until it is filled.
470
-
471
- The project on the wire is the project the sync events carry — the `prj_*` id in
472
- `.kxm/project.yaml`, not the package name. The hub pins a project id to the first
473
- hub project that claims it, so a Runtime that ever pushed under a second label
474
- leaves its own later pushes refused; the supervisor's sync status names that
475
- refusal instead of hiding it.
476
-
477
- Two kinds of hub answer come back, and they are not the same thing. A
478
- **transient** failure (unreachable hub, refused credential) leaves every row
479
- pending, records the reason and backs the next attempt off exponentially. A
480
- **durable** refusal (`sync_sequence_reused`, `sync_project_mismatch`,
481
- `sync_home_runtime_mismatch`, `sync_event_invalid`, a row too large to carry)
482
- takes *that row* out of the pending queue with the hub's code, so one row the hub
483
- will never accept can neither block the rows behind it nor re-alert the hub every
484
- ten seconds. Refused rows are not deleted: `kxm runtime sync-retry` re-queues them
485
- once the hub-side state is corrected, and only an operator decides that a refusal
486
- has become retryable.
487
-
488
- `kxm runtime status` prints what the tick last saw per project — `ok`, `no_hub`,
489
- `blocked` or `refusing`, with pending/acked/refused counts, the refusal codes, the
490
- last failure and the next attempt — read from the supervisor's
491
- `GET /v1/sync/status`. The same transitions are logged to
492
- `$S/runtime/logs/kxm-runtime.jsonl` (`runtime_sync_state`,
493
- `runtime_sync_stalled`), one line per change: the supervisor runs detached with no
494
- stdio, so that file and that endpoint are its only voice.
495
-
496
- `GET /v1/ops/snapshot` adds `homeRuntimes`: synchronized runs grouped by home
497
- Runtime, each with its bounded title/status, `lastSequence`, `pendingGap`, and
498
- `orphaned` once the Runtime's presence lease (`heartbeatAt + staleAfterMs`, hub
499
- clock) has lapsed. Orphaned is view state; nothing is migrated.
500
- `kxm_sync_events_accepted_total`, `kxm_sync_events_duplicate_total`,
501
- `kxm_sync_events_refused_total`, `kxm_sync_conflicts_total` and
502
- `kxm_runtime_heartbeats_total` are in `/metrics`.
503
-
504
- ## Hub Q&A / knowledge base
505
-
506
- - [What is all stored on the hub?](kb/qa-what-the-hub-stores.md)
507
- - [Storage engine — SQLite vs DuckDB](kb/qa-sqlite-vs-duckdb.md)
508
- - [Hub on a public host — multiple users and projects?](kb/qa-hub-on-a-public-host.md)
509
- - [Authentik at the edge: why the hub owns no browser identity](kb/qa-authentik-authentication.md)
510
- - [Extension install → kxm CLI bootstrap + hub auto-connect](kb/qa-extension-install-and-hub-bootstrap.md)
@@ -1,67 +0,0 @@
1
- # This host's Pi packages
2
-
3
- Snapshot of the operator Pi user packages and file extensions on this KXM
4
- development host (2026-09-10). It is **not** a KXM install requirement and is
5
- **not** copied by `kxm init`. `pi list` is authoritative; this page is a
6
- checked-in copy for agents working in this repository.
7
-
8
- ## User packages (`pi list`)
9
-
10
- | Source | Version | What it loads |
11
- |---|---|---|
12
- | `npm:pi-antigravity` | 0.7.2 | Antigravity / Cloud Code Assist provider (`./src/index.ts`) |
13
- | `git:git@github.com:kontextmind/kxm.git@main` | 0.6.0 (`10a1b77` at snapshot) | KXM Pi extension and Agent Skills |
14
- | `npm:@xynogen/pix-core` | 0.5.38 | pix UI/tool aggregator (`src/extension.ts`); activates bundled pix members, not separate `pi list` sources |
15
- | `npm:@tian.zuo/pi-antigravity` | 0.10.3 | Antigravity via `agy` stream-json (`./index.ts`) |
16
- | `npm:@latentminds/pi-quotas` | 0.5.0 | Quota and usage status commands |
17
- | `npm:pi-provider-kimi-code` | 0.6.12 | Kimi Code provider (`./index.ts`) |
18
-
19
- Install roots on this host:
20
-
21
- - npm: `%USERPROFILE%\.pi\agent\npm\node_modules\`
22
- - git KXM: `%USERPROFILE%\.pi\agent\git\github.com\kontextmind\kxm`
23
-
24
- Project-local Pi extension (gitignored `.pi/`): `.pi/extensions/rtk.ts` from
25
- `rtk init --agent pi`. User-level `~/.pi/agent/extensions/rtk.ts` is also
26
- installed.
27
-
28
- ## File extensions
29
-
30
- Loaded from `%USERPROFILE%\.pi\agent\extensions\` (not shown by `pi list`):
31
-
32
- | File | Role |
33
- |---|---|
34
- | `rtk.ts` | RTK bash rewrite via `rtk rewrite`; needs `rtk` 0.23 or newer on `PATH` |
35
- | `quotas.json` | Config for `@latentminds/pi-quotas`, not an extension factory |
36
-
37
- `rtk` 0.48.0 is installed as winget `rtk-ai.rtk`. New shells pick up the User
38
- `PATH` entry. `pix-core` also activates `pix-optimizer`, which can rewrite
39
- commands for RTK independently of `rtk.ts`.
40
-
41
- ## Notes
42
-
43
- - The antigravity provider is bundled inside `plugins/kxm` (vendored from
44
- pi-antigravity, MIT); remove any standalone pi-antigravity Pi extension to
45
- avoid the double-registration warning. `pi-antigravity` and
46
- `@tian.zuo/pi-antigravity` are different Pi providers. For Google, this bundled
47
- provider **is** the admitted route (Tracking → Decided, 2026-09-15); `agy` stays a
48
- catalog/helper entry rather than the admission path.
49
- - For KXM development loads, prefer the working tree:
50
- `pi --no-extensions -e ./plugins/kxm/src/extension.ts`. Add every required
51
- provider extension with another `-e`; otherwise Pi discovery is disabled.
52
- See [Troubleshooting](troubleshooting.md#pi-shows-huboff).
53
- - Refresh this page when `pi list` or
54
- `%USERPROFILE%\.pi\agent\extensions\` changes.
55
-
56
- ## Project-scoped RTK (this checkout)
57
-
58
- `rtk init` in this repository (2026-09-10). Not copied by `kxm init`.
59
-
60
- | Path | Role |
61
- |---|---|
62
- | `RTK.md` | Slim RTK instructions for Codex and `@RTK.md` includes |
63
- | `AGENTS.md` | `@RTK.md` reference (Codex / Kimi) |
64
- | `CLAUDE.md` | `@RTK.md` reference (Claude Code) |
65
- | `.rtk/filters.toml` | Project filter template |
66
- | `.agents/rules/antigravity-rtk-rules.md` | Antigravity rules |
67
- | `.pi/extensions/rtk.ts` | Project Pi rewrite extension (gitignored) |