@kontextmind/kxm 0.7.95 → 0.7.96

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 (140) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.kxm/README.md +39 -9
  3. package/CHANGELOG.md +1 -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 +152 -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 +364 -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 +265 -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} +83 -41
  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/package.json +1 -1
  88. package/packages/core/tui/README.md +1 -1
  89. package/plugins/kxm/.claude-plugin/plugin.json +1 -1
  90. package/plugins/kxm/README.md +31 -32
  91. package/plugins/kxm/dist/cli.js +5 -5
  92. package/plugins/kxm/dist/mcp-server.js +1 -1
  93. package/plugins/kxm/dist/runtime.js +1 -1
  94. package/plugins/kxm/package.json +1 -1
  95. package/plugins/kxm/skills/kxm/references/protocol.md +3 -1
  96. package/plugins/kxm/skills/kxm-browser-auth/SKILL.md +1 -1
  97. package/plugins/kxm/skills/kxm-browser-diagnostics/SKILL.md +5 -5
  98. package/plugins/kxm/skills/kxm-browser-explore/SKILL.md +2 -2
  99. package/plugins/kxm/skills/kxm-browser-session/SKILL.md +10 -13
  100. package/plugins/kxm/skills/kxm-browser-takeover/SKILL.md +1 -1
  101. package/plugins/kxm/skills/kxm-browser-verify/SKILL.md +1 -1
  102. package/plugins/kxm/skills/kxm-context-memory/SKILL.md +13 -4
  103. package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +3 -1
  104. package/plugins/kxm/skills/kxm-mind-setup/SKILL.md +2 -1
  105. package/plugins/kxm/skills/kxm-project-setup/SKILL.md +31 -54
  106. package/plugins/kxm/skills/kxm-projects/SKILL.md +1 -1
  107. package/plugins/kxm/skills/kxm-protocol/SKILL.md +1 -1
  108. package/plugins/kxm/skills/kxm-routing-improve/SKILL.md +15 -7
  109. package/plugins/kxm/skills/kxm-runs/SKILL.md +11 -5
  110. package/plugins/kxm/skills/kxm-session/SKILL.md +1 -1
  111. package/plugins/kxm/skills/kxm-tasks/SKILL.md +9 -7
  112. package/plugins/kxm/skills/kxm-workflow/SKILL.md +10 -2
  113. package/plugins/kxm/src/cli/system.ts +1 -1
  114. package/plugins/kxm/src/cli.ts +3 -3
  115. package/plugins/kxm/src/init-guide-setup.ts +1 -1
  116. package/plugins/kxm/src/mcp-server.ts +1 -1
  117. package/plugins/kxm/src/modes.ts +1 -1
  118. package/schemas/README.md +1 -1
  119. package/docs/agent-communication-envelopes-and-gates.md +0 -553
  120. package/docs/agent-skills.md +0 -198
  121. package/docs/architecture.md +0 -245
  122. package/docs/assignment-runner.md +0 -264
  123. package/docs/browser-automation.md +0 -139
  124. package/docs/configuration.md +0 -437
  125. package/docs/continuous-improvement.md +0 -226
  126. package/docs/getting-started.md +0 -277
  127. package/docs/harness-routing.md +0 -616
  128. package/docs/kb/qa-authentik-authentication.md +0 -97
  129. package/docs/kb/qa-extension-install-and-hub-bootstrap.md +0 -85
  130. package/docs/kb/qa-hub-on-a-public-host.md +0 -48
  131. package/docs/kb/qa-sqlite-vs-duckdb.md +0 -35
  132. package/docs/kb/qa-what-the-hub-stores.md +0 -64
  133. package/docs/kxm-handbook.md +0 -1181
  134. package/docs/operations.md +0 -510
  135. package/docs/operator-pi-packages.md +0 -67
  136. package/docs/provenance-gates.md +0 -295
  137. package/docs/skills.md +0 -47
  138. package/docs/test-matrix.md +0 -132
  139. package/docs/troubleshooting.md +0 -322
  140. package/docs/webhook-workflows.md +0 -240
@@ -1,97 +0,0 @@
1
- ---
2
- schema: "kxm.doc.v1"
3
- id: "KB-HUB-001"
4
- type: "kb"
5
- title: "Q&A: Authentik (OIDC) for user/role/agent authentication"
6
- project: "kxm"
7
- status: "draft"
8
- owner: "@operator"
9
- created: "2026-09-17"
10
- updated: "2026-09-18"
11
- authority: "hypothesis"
12
- confidence: "uncertain"
13
- summary: "Authentik authenticates browsers at the reverse proxy and the tenant portal's backend calls the loopback hub with existing machine tokens. KXM does not interpret browser identity headers, and the hub-side JWT verification and token broker once recommended here are rejected, not deferred."
14
- tags: ["hub", "authentik", "oidc", "auth"]
15
- related: ["docs/operations.md", "docs/kb/qa-hub-on-a-public-host.md", "plans/plan-per-tenant-hosting.md", "plans/implementation-plan.md"]
16
- ---
17
-
18
- # Q&A: Authentik (OIDC) for user/role/agent authentication
19
-
20
- > Researched by `claude --model fable` (planner, read-only) · 2026-09-17 · task_c0bb05339e15 · root review: pending
21
-
22
- **Short answer, as of 2026-09-20: no hub-side identity subsystem at all.** Authentik
23
- authenticates browsers at the tenant's reverse proxy and the portal's own backend calls the
24
- loopback hub with the machine tokens that already work. The token-broker and JWT
25
- recommendations that used to sit in this answer are **rejected**, not deferred; they were
26
- plausible for a shared multi-tenant hub, which is not what we are deploying. Option 1 below —
27
- forward-auth at the existing proxy, hub unchanged — is the **selected** shape; options 2 and 3
28
- are rejections, not stages.
29
-
30
- ## What exists today
31
-
32
- The hub knows about three credentials. None of them carries a user identity, a role, or a group.
33
-
34
- 1. **Static admin token.** `MeshHubOptions.authToken` (`plugins/kxm/src/hub.ts:77`) is compared with `safeTokenEqual` (`hub.ts:126`, delegating to the SHA-256 `timingSafeEqual` in `commands.ts:937`) against the `Authorization: Bearer` header parsed by `bearerToken` (`hub.ts:130`). `requireAdminAuth` (`hub.ts:533`) gates `/metrics` (`hub.ts:1390`) and admin-scoped context calls (`hub.ts:525`). `requireConfiguredAdminAuth` (`hub.ts:543`) returns 503 `admin_auth_not_configured` when no token is set, gating `/v1/ops/snapshot` and `/v1/ops/events` (`hub.ts:1396`, `1406`) and workflow degradation. The token is sourced from `KXM_AUTH_TOKEN` (`server.ts:15`) or resolved via `resolveHubCredentials` (`hub-env.ts:140`), which generates `kxm_admin_<24 random bytes>` (`hub-env.ts:44`) and persists it to `hub-env.json` with mode 0600 (`hub-env.ts:86`). Auto-start injects it into the hub child's env (`hub-autostart.ts:175`).
35
- 2. **Per-project tokens.** `KXM_PROJECT_TOKENS` is a JSON map of project name to bearer string (`server.ts:45`, `hub-env.ts:120`). `expectedProjectToken` falls back to the admin token when no project token exists (`hub.ts:495`). `requireProjectAuth` (`hub.ts:499`) throws 401 `invalid_auth` on mismatch. Every agent-facing route calls `requireAgent` then `requireProjectAuth(request, agent.project)` (e.g. `hub.ts:1432`, `2133`, `2200`).
36
- 3. **Agent identity (name + key).** `POST /v1/agents/register` (`hub.ts:2091`) accepts a free-form `name`, `purpose`, `project`, `model`, requires only the project token, and mints a fresh `key` via `newId("key")` on every registration or resume (`hub.ts:2107`, `2115`). Name uniqueness is enforced only against currently online agents in the same project (`hub.ts:2098`). The record is stored as opaque JSON in the `agents` table (`store.ts:26`); `AgentRecord` (`protocol.ts:19`) has no role, owner, or principal field. Clients send `x-kxm-agent-id` and `x-kxm-agent-key` headers (`client.ts:540`), which `requireAgent` checks with `safeTokenEqual` (`hub.ts:554`).
37
-
38
- **Fail-open edges to preserve or close.** With no admin token on a loopback bind, `requireAdminAuth` returns without checking (`hub.ts:534`) and `requireProjectAuth` skips when no expected token exists (`hub.ts:501`); `server.ts:92` warns `auth=none`. A non-loopback bind without a token refuses to start (`hub.ts:468`). Repo rule: "Bypass fail-closed identity checks" is on the do-not list (`AGENTS.md:224`).
39
-
40
- **Roles and permissions today are not hub-authenticated.** Role definitions map to a `tools` allow/deny/preset block (`role.ts:63`-`137`), and the `role` on `/v1/context/get` is a caller-asserted string used only to pick a context budget and journal categories (`hub.ts:1578`, `arbiter.ts:81`). Tool policy is enforced client-side by `enforceToolPolicy` (`commands.ts:1125`), called from the MCP server (`mcp-server.ts:115`), the Pi extension (`extension.ts:892`), and the CLI (`cli.ts:220`). It reads `KXM_ATTEMPT_TOKEN`, then `KXM_SESSION_TOKEN`, then the on-disk `session.token` (`commands.ts:1130`, `1166`, `1182`), and returns `tool_policy_denied` when `isToolAllowed` (`commands.ts:1086`) rejects. Both token formats are unsigned base64url JSON (`mintAttemptToken` `commands.ts:916`, `mintSessionToken` `commands.ts:977`); `parseSessionToken` checks only schema and expiry (`commands.ts:998`). `kxm auth token --issue` mints an `operator` preset locally with no external identity (`cli/hub.ts:500`). The Studio mutate endpoint compares its session token with plain `!==` rather than the timing-safe helper (`studio-layout.ts:350`). No OIDC, JWT, or JWKS code exists in the repo; the only hits are prose in a role description (`init-guide-setup.ts:136`). The plugin has no JWT dependency (`plugins/kxm/package.json:9`).
41
-
42
- ## Integration options
43
-
44
- ### 1. Reverse-proxy forward-auth (Authentik outpost at the proxy; hub unchanged) — **selected shape at the edge**
45
-
46
- Authentik's proxy outpost authenticates browser sessions and passes headers upstream. The hub ignores those headers today, and under the per-tenant decision it keeps ignoring
47
- them: the **portal's own backend** holds the hub bearer server-side and calls loopback, while
48
- the proxy's job is to keep the hub's routes off the public interface entirely. Do not
49
- configure the proxy to inject the admin token on behalf of every user — that flattens all
50
- Authentik users to hub admin. What this option does **not** give the hub is per-user identity
51
- for logging, which is the portal's to record. Effort: low, config only. Risk: low if the hub keeps its token check; medium if someone sets the proxy to add the admin token for every authenticated user, which flattens all Authentik users to admin. Non-loopback bind already requires a token (`hub.ts:468`), so the proxy cannot make the hub anonymous.
52
-
53
- ### 2. Hub validates Authentik-issued JWTs (OIDC discovery + JWKS) — **rejected 2026-09-20; a new decision is required to revisit**
54
-
55
- Add a second accepted credential in `bearerToken`'s callers: if the bearer parses as a JWT, verify `iss`, `aud`, `exp`, and signature against a cached JWKS from `<issuer>/.well-known/openid-configuration`; else fall through to the existing `safeTokenEqual` path. Code changes: a new `oidc.ts` (discovery, JWKS cache, verify via `node:crypto` `createPublicKey` from JWK, or add `jose`), new `MeshHubOptions.oidc` and `KXM_OIDC_ISSUER` / `KXM_OIDC_AUDIENCE` env in `server.ts` and `hub-env.ts`, and changes to `requireAdminAuth` and `requireProjectAuth` to accept a verified claim set. Mapping: `groups` claim to admin (e.g. `kxm-admin`) and to project scope (e.g. `kxm-project:<name>`). Client side: `HubClient.authToken` (`client.ts:539`) already sends any string as bearer, so a client can pass an Authentik access token unchanged. Effort: medium, roughly 300 to 500 lines plus tests. Risk: medium. New network dependency at auth time (JWKS fetch must fail closed, never skip), clock skew, and the hub must reject `alg: none` and HS256. Agent registration would gain a real principal to store on the agent record (`sub`, `preferred_username`), which the schema can absorb since records are opaque JSON (`store.ts:26`).
56
-
57
- ### 3. Token-broker mapping (Authentik users/groups mint per-user or per-agent kxm tokens) — **rejected 2026-09-20; a new decision is required to revisit**
58
-
59
- A small broker (could be a new hub route or a sidecar) accepts an Authentik ID token, verifies it as in option 2, then issues the tokens the runtime already consumes: a project token entry for `requireProjectAuth`, and a `kxm.session-token.v1` with a `toolPolicy` derived from the user's group (`mintSessionToken`, `commands.ts:944`). Mapping table: Authentik group to kxm role id (`role.ts:63` ids `writer`, `planner`, `critic-*`, `verifier`), role `tools` block to `ToolPolicy`, and group to project list to `projectTokens`. Today project tokens are a static map read at startup (`hub.ts:385`), so per-user project tokens need either a dynamic token store in `MeshStore` or short-lived tokens the hub can look up. Session tokens are unsigned (`commands.ts:977`), so a broker-issued one only means something if `parseSessionToken` gains signature verification; otherwise any local process can forge the same payload. Effort: medium to high, because it touches token storage, signing, and revocation. Risk: medium. Benefit: agents and humans converge on one identity source without changing every hub route.
60
-
61
- ## Recommendation (replaced 2026-09-20)
62
-
63
- Options **2 and 3**, and the staged recommendation that used to sit in this section, are
64
- **superseded** — option 1 above is the selected shape, not a rejected one. They stay visible
65
- because they were the plausible answer for a month and someone will meet them again: **do not build a hub-side JWT verifier, a
66
- token broker, per-user project tokens, or signed session/attempt token issuance as hosting
67
- prerequisites.** They were a reasonable answer to "one hub, many users"; they are the wrong
68
- answer to the deployment we actually have, which is **one tenant per box**.
69
-
70
- 1. **Now:** Authentik authenticates and authorizes browsers at the tenant's existing reverse
71
- proxy, on the **portal's** routes. The portal's server-side backend calls the loopback hub
72
- and supervisor using the machine credentials that already work (`KXM_AUTH_TOKEN`,
73
- `KXM_PROJECT_TOKENS`, the persisted hub env record). The hub binds loopback and exposes no
74
- public listener. Nothing in `hub.ts` changes, and no browser identity header reaches it.
75
- 2. **What stays as-is, unmodified:** the admin-token requirement for non-loopback binding, the
76
- generated-and-persisted token, project tokens read at startup, and the local loopback
77
- convenience. A browser-path outage denies browsers; it must not stop authorized machine
78
- clients.
79
- 3. **Rejected, not deferred:** hub-side JWT verification, group-to-`ToolPolicy` mapping,
80
- token signing, dynamic per-user token stores, and OAuth2 client-credentials or
81
- device-flow login for agents. These are not waiting for a trigger; they are the wrong
82
- shape for a per-tenant hub, and reopening any of them needs a **new written decision**
83
- that says what the portal boundary cannot do — for example genuine per-user attribution
84
- of hub writes inside KXM itself, which per-box tenancy does not need. Until such a
85
- decision exists, treat every mention of them in this file as history.
86
-
87
- The technical observations underneath remain accurate and are the reason the option is *cheap to
88
- reject*: unsigned session tokens (`commands.ts:977`), static project tokens read at startup
89
- (`hub.ts:385`), a fixed-string `HubClient.authToken`, and a plain-string compare in
90
- `studio-layout.ts:350`. **One item is kept as a live hardening note, not a hosting
91
- prerequisite:** make that Studio compare timing-safe.
92
-
93
- ## Agent auth specifically
94
-
95
- Running agents today authenticate non-interactively with whatever string lands in `HubClient.authToken`, resolved by `resolveClientHubAuthToken` (`hub-env.ts:203`): `KXM_AUTH_TOKEN` env, else the persisted project token, else the persisted admin token. The MCP server (`mcp-server.ts:84`) and the Pi extension (`extension.ts:709`) both use this. Pi worker children inherit `process.env` unchanged (`pi-producer.ts:504`), so they get the same token as the supervisor. Tool policy for workers comes from `KXM_ATTEMPT_TOKEN`, which is minted only in tests today (`test/core/commands-policy.test.ts:60`); no runtime path in `plugins/kxm/src` calls `mintAttemptToken`, so engine issuance is planned but not wired.
96
-
97
- **Superseded paragraph, kept for the record (see the recommendation above):** with Authentik, agents should use the OAuth2 client-credentials grant (one Authentik application per agent class, or per role such as `writer` and `verifier`), obtain an access token at spawn, and pass it as `KXM_AUTH_TOKEN` to the child. This needs option 2 in the hub so the token verifies, and a refresh hook in `HubClient` since `headers()` reads a fixed string (`client.ts:539`) and access tokens expire. Device-code flow is the fallback for Claude Code sessions that start from a human terminal. Whether Authentik's client-credentials tokens carry `groups` claims by default is unknown from this repo; it must be confirmed against the Authentik provider config before mapping roles from claims.
@@ -1,85 +0,0 @@
1
- ---
2
- schema: "kxm.doc.v1"
3
- id: "KB-HUB-002"
4
- type: "kb"
5
- title: "Q&A: Extension install → kxm CLI bootstrap + hub auto-connect"
6
- project: "kxm"
7
- status: "draft"
8
- owner: "@operator"
9
- created: "2026-09-17"
10
- updated: "2026-09-18"
11
- authority: "instruction"
12
- confidence: "reviewed"
13
- summary: "Extension load attempts a hub connection and can auto-start a local hub with generated keys, but it does not bootstrap a global kxm CLI and failure warnings are diagnostic rather than actionable."
14
- tags: ["hub", "extension", "bootstrap", "cli"]
15
- related: ["docs/operations.md", "docs/getting-started.md"]
16
- ---
17
-
18
- # Q&A: Extension install → kxm CLI bootstrap + hub auto-connect
19
-
20
- > Researched by `codex gpt-5.6-sol` (reviewer-cli, read-only) · 2026-09-17 · task_634d24e1225d · root review: pending
21
-
22
- Desired behavior when a user runs `pi install npm:@kontextmind/kxm` and loads the extension:
23
-
24
- 1. the installer/load path checks for, installs, or updates the global `kxm` CLI;
25
- 2. on extension load it attempts to connect to a hub;
26
- 3. if no connection is configured, it starts a local hub with generated API keys and connects;
27
- 4. on failure it shows a friendly warning with brief start/configure instructions.
28
-
29
- ## 1. Does the installer/load path check for, install, or update the global `kxm` CLI?
30
-
31
- Verdict: **MISSING**
32
-
33
- The npm package exposes a `kxm` binary through `"bin": { "kxm": "./scripts/kxm.mjs" }`, and that launcher executes the package's bundled `plugins/kxm/dist/cli.js` (`package.json:53-55`, `scripts/kxm.mjs:6-14`). The same package tells Pi to load the TypeScript extension directly (`package.json:64-70`). However, `extension.ts` contains no CLI presence/version check and no install/update bootstrap. Its only CLI subprocess use is the `/kxm memory` handler, which tries `KXM_BIN || "kxm"` and then a repository-local script fallback (`plugins/kxm/src/extension.ts:944-956`). Update machinery exists, including a global npm install plan (`plugins/kxm/src/kxm-update.ts:215-237`), but it is reached through the explicit `kxm update --kxm` command (`plugins/kxm/src/cli.ts:446-460`). That command deliberately applies package updates only when the current install is classified as `npm-global`; Pi-managed installs are classified as `pi-git` and told to use `pi update` (`plugins/kxm/src/kxm-install-kind.ts:59-75`, `plugins/kxm/src/cli/system.ts:356-376`). Whether Pi itself creates a globally discoverable binary for an npm package is unknown from this repository; no repository code requests or verifies that outcome.
34
-
35
- ## 2. On extension load, does it attempt to connect to a hub?
36
-
37
- Verdict: **PARTIAL**
38
-
39
- On every Pi `session_start`, the extension stops any previous client, derives the project and agent identity, optionally runs hub auto-start, constructs a `HubClient`, and calls `client.start(receive)` (`plugins/kxm/src/extension.ts:657-730`). It reports a successful connection in Pi with an info notification and reports a failed connection with an error notification (`plugins/kxm/src/extension.ts:730-751`). The gap is configured hub binding: `ensureHubRunning()` reads the persisted binding, probes it, and returns `bound-healthy` when it is available (`plugins/kxm/src/hub-autostart.ts:130-136`), but `extension.ts` computes `serverUrl` only from `KXM_SERVER_URL` or the localhost default before auto-start and never replaces it with the binding URL or the returned URL (`plugins/kxm/src/extension.ts:679-692`, `plugins/kxm/src/extension.ts:718-725`). By contrast, the CLI's runtime resolution explicitly uses `KXM_SERVER_URL`, then the bound hub URL, then localhost (`plugins/kxm/src/cli/types.ts:238-252`). Therefore extension load attempts a connection, but a healthy persisted remote binding can be detected and then ignored unless `KXM_SERVER_URL` is also set.
40
-
41
- ## 3. If no connection is configured, does it start a local hub with generated API keys and connect to it?
42
-
43
- Verdict: **EXISTS TODAY**
44
-
45
- Hub auto-start defaults to `background` in the resolved configuration (`plugins/kxm/src/config.ts:111-132`), and unknown auto-start values also resolve to `background` (`plugins/kxm/src/hub-autostart.ts:60-65`). `ensureHubRunning()` first checks a bound hub, a live local PID claim, and the configured/default URL; if none is live, it resolves credentials, launches the packaged `scripts/kxm-hub.mjs` wrapper in the background, and waits for a hub claim (`plugins/kxm/src/hub-autostart.ts:126-167`, `:185-213`). Credential resolution prefers an environment token, then the persisted user-state token, otherwise generates a URL-safe admin token and persists it (`plugins/kxm/src/hub-env.ts:135-182`); the persisted file is written through a temporary file with mode `0600` (`hub-env.ts:86-98`). The generated/reused token is injected into the hub process (`hub-autostart.ts:169-180`) and then supplied to the extension's `HubClient`, after which `client.start()` connects (`extension.ts:688-729`). The generated credential is specifically one admin token; `projectTokens` may be loaded from configuration but are not generated here (`hub-env.ts:157-168`). Also, auto-start verifies the wrapper's PID claim rather than hub HTTP readiness, so a fast client connection can theoretically race server readiness; whether `HubClient.start()` retries that race is unknown without treating code outside the requested bootstrap path as evidence.
46
-
47
- ## 4. On failure, does it show a friendly warning with brief start/configure instructions?
48
-
49
- Verdict: **PARTIAL**
50
-
51
- Failures are surfaced in Pi's notification UI, but the messages are diagnostic rather than actionable. A structured auto-start failure produces `kxm hub auto-start failed: <reason> (log: <path>)`, thrown setup errors produce a similar warning, malformed persisted credentials produce another warning, and final connection failure produces `kxm connection failed: <error>` (`plugins/kxm/src/extension.ts:700-715`, `:749-752`). The extension already has a `/kxm hub` view that reports health and connection state (`plugins/kxm/src/extension.ts:348-362`, `:911-915`), and its general help mentions `kxm hub view` (`plugins/kxm/src/extension.ts:940-942`). None of the load-time failure messages tells the user to run `kxm hub start`, configure `KXM_SERVER_URL`, or persist a remote endpoint with `kxm hub bind <url>`. The current warning also assumes the `kxm` executable is available, which the extension does not verify.
52
-
53
- ## Gap list
54
-
55
- 1. **Global CLI bootstrap/preflight.** Add a bootstrap helper invoked before hub startup in the `session_start` handler, immediately before `loadKxmConfig()`/`ensureHubRunning()` at `plugins/kxm/src/extension.ts:688-692`. It should distinguish "the Pi package contains the CLI" from "a global `kxm` command is installed", probe `KXM_BIN`/PATH and version, and return a structured result. Automatic installation or updating should reuse narrowly factored primitives from `planKxmPackageUpdate()` rather than shell-form commands.
56
- **Risk:** this crosses the Pi-package/global-CLI ownership boundary. A Pi-installed extension is currently classified as `pi-git` and intentionally updated through `pi update`, while `kxm update --kxm` rejects non-global installs (`kxm-install-kind.ts:59-75`, `cli/system.ts:356-376`). Silently installing a second global copy could create version skew, PATH ambiguity, unexpected network writes, or privilege prompts. Fail closed on ambiguous ownership and do not overwrite an independently managed global installation. On Windows, executable lookup and npm invocation may require `kxm.cmd`/`npm.cmd`; PATH changes made by npm may not enter the already-running Pi process.
57
-
58
- 2. **One authoritative endpoint resolver for the extension.** Import and use `readHubBinding()` in `extension.ts`, or extract the CLI precedence into a shared resolver, then resolve the client URL as explicit `KXM_SERVER_URL` → valid persisted binding → localhost. Hook this before the current `serverUrl` assignment at `plugins/kxm/src/extension.ts:679`; alternatively, carry the `url` from `ensureHubRunning()`'s `bound-healthy`/`url-healthy` results into `HubClient`.
59
- **Risk:** malformed binding records already fail closed in `readHubBinding()` (`hub-binding.ts:78-107`). The extension should warn and avoid silently redirecting to localhost when an explicit or persisted remote configuration is malformed. It must also preserve the existing rule that URL credentials, query strings, and fragments are rejected (`hub-binding.ts:44-63`).
60
-
61
- 3. **Readiness-aware local startup/connect.** After `ensureHubRunning()` returns `started` or `claim-alive`, probe the selected URL until `/health` is ready within a bounded timeout, or add bounded retry behavior around `client.start()`. The natural hooks are the end of `ensureHubRunning()` at `hub-autostart.ts:185-213` or immediately before `client.start()` at `extension.ts:728-730`.
62
- **Risk:** retries must remain bounded and must not start a second hub merely because HTTP readiness lags the PID claim. Errors and log excerpts must continue through secret redaction; `hub-autostart.ts` currently redacts the log tail (`hub-autostart.ts:115-120`). Windows uses `detached: false` while hiding the child window (`hub-autostart.ts:177-180`), so lifecycle and shutdown behavior need Windows-specific verification.
63
-
64
- 4. **A shared actionable warning formatter.** Add a small formatter for auto-start, credential, and connection failures and call it from the existing catch/result branches at `plugins/kxm/src/extension.ts:700-715` and `:749-752`. It should account for CLI-preflight state so it never recommends an unavailable bare `kxm` command without also giving the Pi-package recovery path.
65
- **Risk:** do not include authentication tokens, environment dumps, or unredacted server responses. Instructions must distinguish local start from remote binding and must not silently weaken malformed-binding or credential failures by falling back to an unauthenticated hub. Windows commands should avoid Unix-only path or shell syntax.
66
-
67
- 5. **Coverage for the complete extension bootstrap sequence.** Extend the existing extension and hub-autostart tests around the actual `session_start` flow: global CLI missing/current/stale; healthy persisted binding; no binding leading to generated credentials and local startup; startup readiness race; malformed binding/credential files; and warning text. Tests must not perform real global npm installation or modify the developer's user state: inject executable probes, spawners, environment, fetch, and temporary state roots. Include Windows path casing, `.cmd` resolution, `LOCALAPPDATA`, and non-detached process behavior.
68
-
69
- ## Recommended UX for the friendly warning
70
-
71
- Surface one `warning` notification through `ctx.ui.notify()` during Pi `session_start`, where the current auto-start warnings already appear. Keep the status/widget available through `/kxm hub`, but do not shut down the Pi session for an ordinary hub failure.
72
-
73
- Recommended copy:
74
-
75
- > KXM couldn't connect to a hub. Start a local hub with `kxm hub start`, or connect this machine to an existing hub with `kxm hub bind <url>` (you can also set `KXM_SERVER_URL`). Run `/kxm hub` to check status. Details: `<short redacted reason>`.
76
-
77
- If the CLI preflight says no global command is available, replace the first instruction with:
78
-
79
- > The KXM extension is loaded, but the global `kxm` CLI is unavailable. Install it with `npm install --global @kontextmind/kxm`, then run `kxm hub start`; or configure an existing hub with `KXM_SERVER_URL`.
80
-
81
- If the package is Pi-managed and global installation is intentionally not automatic, say so explicitly:
82
-
83
- > Update the Pi package with `pi update`; global CLI installation is separate.
84
-
85
- The notification should remain brief, show the redacted log path when auto-start created one, and use Pi's existing warning surface at `plugins/kxm/src/extension.ts:700-705`. The final failed `client.start()` notification at `plugins/kxm/src/extension.ts:749-752` should use the same formatter so users receive one consistent recovery path rather than two unrelated errors.
@@ -1,48 +0,0 @@
1
- ---
2
- schema: "kxm.doc.v1"
3
- id: "KB-HUB-003"
4
- type: "kb"
5
- title: "Q&A: Hub on a public host — multiple users and projects?"
6
- project: "kxm"
7
- status: "draft"
8
- owner: "@operator"
9
- created: "2026-09-17"
10
- updated: "2026-09-18"
11
- authority: "instruction"
12
- confidence: "reviewed"
13
- summary: "One hub is one process and one state set per tenant box behind a TLS proxy; it is not multi-tenant and must never be exposed directly to the public internet. Hosting tenancy is the machine plus the portal, and the hub binds loopback."
14
- tags: ["hub", "deployment", "security"]
15
- related: ["docs/operations.md", "docs/kb/qa-authentik-authentication.md", "docs/kb/qa-what-the-hub-stores.md"]
16
- ---
17
-
18
- # Q&A: Hub on a public host — multiple users and projects?
19
-
20
- > Researched by `claude --model fable` (planner, read-only) · 2026-09-17 · task_40b9d5015537 · root review: pending
21
-
22
- ## Deploy today, step by step
23
-
24
- The hub is a single Node process using plain `node:http` (`plugins/kxm/src/hub.ts:3`, `:1099`); there is no HTTPS or TLS code anywhere in the hub, so TLS must be terminated by a reverse proxy in front of it. The bind gate is code-enforced: if `KXM_HOST` is not loopback and no admin token is set, startup throws `KXM_AUTH_TOKEN is required when binding beyond localhost` (`hub.ts:116-119`, `:468-471`). Concretely an operator must:
25
-
26
- 1. Set `KXM_HOST` (defaults to `127.0.0.1`, `server.ts:13`) and `KXM_PORT`. Prefer keeping the hub on loopback or a private interface and letting the proxy reach it; binding `0.0.0.0` is allowed only with a token.
27
- 2. Set `KXM_AUTH_TOKEN` (admin/bearer token, compared with `safeTokenEqual` which wraps a timing-safe compare, `hub.ts:126-133`) and optionally `KXM_PROJECT_TOKENS` as a JSON object of project name to token (`server.ts:45-57`). Under `kxm hub start`, a missing admin token is generated and persisted with mode 0600 to the user state root (`hub-env.ts:44-46`, `:86-99`, `:140-193`, documented in `docs/operations.md:24-34`). The persisted file lives on the hub host, so protect that home directory.
28
- 3. Put a TLS-terminating reverse proxy in front, restrict inbound networks, and disable proxy buffering for the SSE endpoints (`docs/operations.md:181`). `README.md:261` states a non-loopback deployment "requires authentication, TLS termination, process supervision, and network access controls."
29
- 4. Run it under a supervisor with a stable working directory, injected secrets, restart on failure, and at least five seconds of graceful shutdown (`docs/operations.md:38`); the hub handles SIGINT/SIGTERM and closes SQLite (`server.ts:98-111`).
30
- 5. Configure webhook workflows via `KXM_WEBHOOK_WORKFLOWS` or `KXM_WEBHOOK_WORKFLOWS_FILE` (never both, `server.ts:67-74`), with secrets in `secretEnv`/`signalSecretEnv` (`docs/webhook-workflows.md:82-83`, `:103`).
31
- 6. Back up one SQLite file at `KXM_DATA_PATH` (default `.kxm/state/kxm.db`, `server.ts:20-22`). It runs in WAL mode; the documented safe backup is stop the hub, copy the db, restart and check `/ready`; online backups need a SQLite-aware tool or a consistent snapshot of db, `-wal`, and `-shm` (`docs/operations.md:147-160`). The DB is not encrypted at rest (`docs/operations.md:183`). Also back up `.kxm/skills/` and `.kxm/knowledge/` if used (`docs/operations.md:216-219`).
32
- 7. Only `/health` and `/ready` are unauthenticated and bypass rate limiting (`hub.ts:1111-1121`); `/metrics`, `/v1/ops/snapshot`, `/v1/ops/events` require the admin token (`hub.ts:1389-1405`).
33
-
34
- ## Multiple projects
35
-
36
- One process owns one SQLite database (`README.md:255`, `docs/operations.md:3`); there is no per-project DB. Agents, messages, and workflow runs all live in the same tables, with `project` as a column (`store.ts:26-69`). `KXM_PROJECT_TOKENS` isolates only authentication: `requireProjectAuth` compares the bearer to `projectTokens[project] || authToken` (`hub.ts:495-508`). Consequences grounded in that line: a project listed in the map accepts only its own token, not the admin token, on agent routes; any project name not in the map falls back to the admin token, so the admin token can register agents into arbitrary new project names (`hub.ts:2091-2096`). Agents carry a per-agent key header in addition to the project bearer (`hub.ts:554-570`). Context/state operations fail closed across projects (`context_isolation_violation`, `hub.ts:514-531`, `docs/operations.md:223-226`). Whether ordinary peer messages can address an agent in another project is unknown from what was read; message reads are checked per agent id, not per project (`hub.ts:2402-2411`). Webhook workflows are pinned to a project by their definition (`hub.ts:1305`), not by caller token.
37
-
38
- ## Multiple users
39
-
40
- The README classifies the hub as for "local or trusted-team agents" and explicitly "not a horizontally scaled or multi-tenant orchestration service" (`README.md:11`, `:253`), and says "Project tokens isolate hub access by project, but there are no per-user roles or external identity provider" (`README.md:256`). What is actually shared among all users: the one process, the one SQLite file with unencrypted message bodies (`docs/kxm-handbook.md:951`), the hub log at `.kxm/logs/kxm-hub.jsonl` (metadata only, `docs/operations.md:132`), the assets directory for retrospectives (`hub.ts:457-466`), and the in-memory rate-limit table. Blast radius of a leaked project token: register or resume agents in that project, read and send that project's messages, and read that project's context. Blast radius of a leaked admin token: everything above for every unlisted project, plus `/metrics`, ops snapshots and event streams for any project (`hub.ts:1389-1405`), context requests scoped to any project as `kxm-admin` (`hub.ts:525-530`), and workflow degradation approval (`hub.ts:543-552`, `cli/workflows.ts:437`). A leaked webhook `secret` lets an outsider start workflow runs; a leaked `signalSecret` lets them checkpoint waits for a known run and signal key (`hub.ts:1131`, `:1283`, `docs/webhook-workflows.md:137`). Remedy per docs is rotate and reconnect (`docs/operations.md:183`, `:194`).
41
-
42
- ## Honest limits
43
-
44
- Clustering: "no clustering, leader election, or shared-state failover"; do not load-balance across hubs (`README.md:255`, `docs/operations.md:9`). Per-user roles: none, no IdP (`README.md:256`); the only identities are admin token, project token, and per-agent key. Rate limits: one in-memory fixed window keyed by the `x-kxm-agent-id` header, else the socket remote address (`hub.ts:572-590`); counters reset on restart (`README.md:259`); behind a reverse proxy the remote address is the proxy's, and the agent-id header is client-supplied, so this is a courtesy limit, not an abuse control. Webhook replay: HMAC-SHA256 over the exact body with `X-Hub-Signature-256`, no timestamp or nonce (`hub.ts:796-810`); replay is deduplicated by the delivery-id header per run or definition, and a reused id with a different body returns 409 (`hub.ts:1137-1148`, `:1294-1304`, `docs/webhook-workflows.md:135`). A replayed identical delivery is therefore idempotent but not rejected. Delivery is at-least-once, not exactly-once (`README.md:258`). Broader scale needs "shared state and coordination, external identity and fine-grained authorization, distributed traffic controls" (`docs/operations.md:207`). The ops guide states outright: "Never expose the hub directly to the public internet" (`docs/operations.md:183`).
45
-
46
- ## Recommendation
47
-
48
- The smallest defensible topology as-is is one hub bound to loopback on a single host, behind a TLS reverse proxy (Caddy or nginx) that is the only public listener, with an IP allowlist or VPN in front of the proxy, admin token and a distinct project token for every project set via the supervisor's secret injection, webhook secrets set via `secretEnv`/`signalSecretEnv`, proxy buffering off for `/v1/events` and `/v1/ops/events`, and a nightly stopped-hub or SQLite-aware backup of `kxm.db`, `-wal`, `-shm` on encrypted disk. Treat "one hub" as one trust boundary: give one team the admin token and keep every project they run listed in `KXM_PROJECT_TOKENS` so the admin token stops working on agent routes. What not to do yet: serve unrelated teams or customers from one hub (the admin token and the shared unencrypted DB collapse all isolation); expose the port directly without a proxy; rely on the built-in rate limit as abuse protection; run two hubs behind a load balancer; or hand out the admin token to dashboards when a project token would do.
@@ -1,35 +0,0 @@
1
- ---
2
- schema: "kxm.doc.v1"
3
- id: "KB-HUB-004"
4
- type: "kb"
5
- title: "Q&A: Storage engine — SQLite vs DuckDB"
6
- project: "kxm"
7
- status: "draft"
8
- owner: "@operator"
9
- created: "2026-09-17"
10
- updated: "2026-09-18"
11
- authority: "instruction"
12
- confidence: "reviewed"
13
- summary: "The hub already uses SQLite; there is no DuckDB in this repository, and DuckDB should not become the hub's primary store."
14
- tags: ["hub", "sqlite", "storage"]
15
- related: ["docs/operations.md", "docs/kb/qa-what-the-hub-stores.md"]
16
- ---
17
-
18
- # Q&A: Storage engine — SQLite vs DuckDB
19
-
20
- > Answered by root from direct repo evidence · 2026-09-17 · task_279246b4dddb
21
-
22
- **Q: Would you recommend replacing DuckDB for SQLite?**
23
-
24
- **A: The premise is inverted — the hub already uses SQLite. There is no DuckDB anywhere in this repository** (`rg -i duckdb` returns zero matches). The storage engine today is:
25
-
26
- - `plugins/kxm/src/sqlite.ts` — "Runtime-portable SQLite constructor. Prefers Node's built-in `node:sqlite` (the supported runtime for the kxm CLI). Pi loads extensions inside its embedded Bun runtime, which does not provide `node:sqlite`, so fall back to Bun's `bun:sqlite` there."
27
- - Every store builds on `DatabaseSync` from that wrapper: `store.ts` (agents, messages, consumer_cursors, agent_sequences, workflow_runs, workflow_journal, context_items), `runtime-store.ts` (supervisor, projects, runs, events, commands, run_plans), `external-effects.ts` (external_effects).
28
-
29
- **If the real question is "should we ever move to DuckDB?" — no, not as the hub's primary store:**
30
-
31
- 1. **Workload shape.** The hub is OLTP: many small durable reads/writes (message send/deliver/reply, consumer cursors, run state transitions), single-process ownership, WAL mode, point queries by id. That is exactly SQLite's design center. DuckDB is an in-process OLAP/columnar engine built for analytical scans over large datasets — the wrong tool for a message bus.
32
- 2. **Architecture fit.** The README's production boundary is "one process owns one SQLite database; no clustering, leader election, or shared-state failover." SQLite's single-writer model matches that boundary exactly; DuckDB's concurrency model (single writer, bulk loads) does not improve it.
33
- 3. **Runtime fit.** `node:sqlite` is built into Node 22.19+/24 (the documented engines range) and `bun:sqlite` covers Pi's embedded Bun — zero native dependencies, no build step. DuckDB would add a large native dependency to every install for no OLTP benefit.
34
-
35
- **Where DuckDB (or any columnar engine) could make sense later:** analytics over exported telemetry — the routing/cost reports (`kxm routing report`, `just observe-cost`) scan append-only event/journal data. If those scans outgrow SQLite queries, the right shape is a periodic export to a DuckDB file used read-only for analysis, never as the hub's system of record.
@@ -1,64 +0,0 @@
1
- ---
2
- schema: "kxm.doc.v1"
3
- id: "KB-HUB-005"
4
- type: "kb"
5
- title: "Q&A: What is all stored on the hub?"
6
- project: "kxm"
7
- status: "draft"
8
- owner: "@operator"
9
- created: "2026-09-17"
10
- updated: "2026-09-18"
11
- authority: "instruction"
12
- confidence: "reviewed"
13
- summary: "The hub persists agent records, message bodies, workflow runs, journal/evidence, context items, runtime events, and raw tokens in user-state hub-env.json."
14
- tags: ["hub", "storage", "privacy"]
15
- related: ["docs/operations.md", "docs/kb/qa-sqlite-vs-duckdb.md"]
16
- ---
17
-
18
- # Q&A: What is all stored on the hub?
19
-
20
- > Researched by `codex gpt-5.6-sol` (reviewer-cli, read-only) · 2026-09-17 · task_85bd0119c40a · root review: pending
21
-
22
- | store/table or file | what it holds | who writes it | sensitivity (contains secrets? credentials? prompt content?) | retention/cleanup path if any |
23
- |---|---|---|---|---|
24
- | `.kxm/state/kxm.db` — `agents` | Full JSON agent records: ID/key, name, purpose, project, optional model, connection/last-seen timestamps, and online state. `plugins/kxm/src/store.ts:15` · `plugins/kxm/src/protocol.ts:19` | Hub registration/presence code through `MeshStore.saveAgent`. `plugins/kxm/src/store.ts:233` | No credential field by design. Operator-entered names/purposes may still be sensitive. No storage-time redaction is performed by `saveAgent`. | No automatic agent-row retention or deletion was found. Full reset: stop the hub, then remove `kxm.db` and its `-wal`/`-shm` sidecars. Not safe to delete while running. |
25
- | `.kxm/state/kxm.db` — `messages` | The complete peer/workflow message JSON, including sender/recipient, routing metadata, timestamps/status, **request body in `content`**, and **reply body in `reply.content`**. Workflow-generated messages can contain a rendered webhook payload because templates are rendered into the stored prompt. `plugins/kxm/src/protocol.ts:72` · `plugins/kxm/src/hub.ts:1320` | Hub peer-message, reply, cancellation, expiry, and workflow transition paths through `saveMessage`/`saveWorkflowTransition`. `plugins/kxm/src/store.ts:241` | **Yes: prompt/message/reply content is stored.** There is no general redaction call in `saveMessage`; therefore a token or secret included in content can reach SQLite. | Terminal messages (`replied`, `cancelled`, `expired`, `error`) are swept after `KXM_MESSAGE_RETENTION_MS`, default 7 days; nonterminal queued/delivered messages are not age-purged by that sweep. Individual cancellation does not immediately erase the body. `plugins/kxm/src/protocol.ts:6` · `plugins/kxm/src/store.ts:438` |
26
- | `.kxm/state/kxm.db` — `consumer_cursors` | Per-agent last-consumed message sequence. `plugins/kxm/src/store.ts:44` | Hub delivery/consumer acknowledgement path through `advanceCursor`. `plugins/kxm/src/store.ts:321` | No bodies or credentials; agent IDs and delivery position only. | No row-level cleanup found. Reset with the whole hub DB while stopped; manually deleting only this table would disturb delivery semantics and is unsupported. |
27
- | `.kxm/state/kxm.db` — `agent_sequences` | Per-agent next message sequence used for ordered delivery. `plugins/kxm/src/store.ts:48` | Hub message allocation through `nextAgentSequence`. `plugins/kxm/src/store.ts:280` | No bodies or credentials; agent IDs and counters only. | No row-level cleanup found. Reset with the whole hub DB while stopped. |
28
- | `.kxm/state/kxm.db` — `workflow_runs` | Complete workflow-run JSON: workflow/source/delivery IDs, payload and definition hashes, project and target identities, linked message ID, status, stage definitions/state, waits, signal receipts, evidence maps, transitions, captured oracle/plan hashes, and timestamps. The raw webhook body is not stored here, but its SHA-256 and any values incorporated into stages or stored evidence are. `plugins/kxm/src/workflow.ts:301` | Hub webhook/workflow coordinator through `saveWorkflowRun` and transactional workflow transitions. `plugins/kxm/src/store.ts:536` | Contains workflow instructions, summaries, evidence, hashes and operational metadata. Evidence values are accepted without `redactSecrets`, so they may contain submitted secret material. Workflow definition secrets are excluded from `definitionHash`. `plugins/kxm/src/hub.ts:248` · `plugins/kxm/src/workflow.ts:1184` | Completed/failed runs older than the run-retention default of 7 days are swept, together with their journal rows. Active/nonterminal runs are retained. `plugins/kxm/src/store.ts:483` |
29
- | `.kxm/state/kxm.db` — `workflow_journal` | Full journal entries: run/agent/stage/attempt IDs, category, area, severity, summary, optional details, evidence strings, related entries, promotion history, and timestamps. `plugins/kxm/src/workflow.ts:340` | Hub checkpoint, signal, error, workflow-record, transition and promotion paths through `saveJournalEntry`. `plugins/kxm/src/store.ts:544` | **Yes: evidence/journal content is stored.** Summary, details and evidence are not generally secret-redacted before persistence; they can contain sensitive operational or prompt-derived content. | Removed with an expired terminal run. Orphan journal rows older than the same 7-day run-retention window are also swept. `plugins/kxm/src/store.ts:496` |
30
- | `.kxm/state/kxm.db` — `context_items` | Full context item JSON: project/scope/kind, summary, provenance/source reference/lineage, authority/confidence, state key and temporal validity, lifecycle status, supersession and evidence references. `plugins/kxm/src/context.ts:110` | Hub context/memory endpoints through `saveContextItem`. `plugins/kxm/src/store.ts:552` | Summary and provenance `sourceRef` are passed through `redactSecrets`; reserved credential/control-plane fields are rejected. Redaction is pattern-based, so unrecognized secrets or sensitive prose may remain. `plugins/kxm/src/context.ts:204` | Superseded/rejected items, or expired items, are removed once their terminal timestamp is beyond the 7-day run-retention cutoff. Current items have no general TTL. `plugins/kxm/src/store.ts:518` |
31
- | Hub DB schema metadata/migrations | SQLite `user_version`; current hub-store version is 3. Migration 1→2 adds agents/messages/workflow runs/journal; 2→3 adds context items, message indexes, consumer cursors and agent sequences. `plugins/kxm/src/store.ts:76` | `openDatabase` during hub startup. | No content beyond schema/version metadata. | Automatic forward migration only along declared lanes. Wiping the DB discards all hub-store data and recreates the current schema on next start. |
32
- | User-state `runtime/registry.db` — `supervisor` | Singleton runtime identity, PID, port, **token hash**, start/heartbeat times and lifecycle state. `plugins/kxm/src/runtime-store.ts:92` | KXM runtime supervisor claim, heartbeat, takeover and shutdown paths. | Contains only the hash of the runtime token, not the raw token; also exposes process/port/liveness metadata. | No automatic retention found; the singleton is updated in place. Stop the runtime before wiping `registry.db`. Removing it also loses authoritative project-home registration state. |
33
- | User-state `runtime/registry.db` — `projects` | Project ID, canonical absolute project root, derived project key, immutable home-runtime ID, optional config revision and registration time. `plugins/kxm/src/runtime-store.ts:110` | KXM `openKxmRuntimeContext`/runtime registration. `plugins/kxm/src/runtime-service.ts:268` | No credentials or prompt body. Absolute filesystem paths and project identities may be sensitive. | No unregister/retention path was found. Stop the runtime before deleting the registry. Deleting it alone leaves per-project event stores orphaned on disk. |
34
- | User-state `runtime/projects/<projectKey>/run-events.db` — `runs` | Run/project/runtime/workflow IDs, **prompt SHA-256 rather than prompt text**, status, pinned config/memory/executor/tool-policy revisions, and timestamps. `plugins/kxm/src/runtime-store.ts:583` | KXM runtime run creation/status updates. | No raw prompt in this table. IDs, revisions and prompt hash are operationally sensitive. | No automatic run retention or delete path found. Wipe the project’s complete runtime directory while the supervisor/runtime is stopped. |
35
- | Same `run-events.db` — `events` | Immutable ordered run-event stream: event identity/type, optional command ID, times/sequence, revision pins, home runtime, schema and arbitrary JSON `payload`. `plugins/kxm/src/runtime-store.ts:598` | KXM runtime/engine through `appendEvent`. `plugins/kxm/src/runtime-store.ts:891` | Event payloads can contain instructions, evidence, summaries, tool outcomes or other run content. No general `redactSecrets` call occurs in `appendEvent`; secret exposure depends on each producer. | No automatic retention/delete path found. Treat as an append-only audit log; reset the whole project event store while stopped. |
36
- | Same `run-events.db` — `commands` | Idempotent command ID, run ID, command kind, arbitrary JSON result and recorded time. `plugins/kxm/src/runtime-store.ts:618` | KXM command handlers through `insertCommand`. `plugins/kxm/src/runtime-store.ts:826` | Command results may include sensitive run/output content; no general storage redaction is applied here. | No automatic retention/delete path found. Reset with the project event store while stopped. |
37
- | Same `run-events.db` — `run_plans` | Run ID, run-plan hash, full pinned serialized plan envelope, and sequence where it was pinned. `plugins/kxm/src/runtime-store.ts:625` | KXM plan compilation/pinning code. | Contains workflow/step instructions and policy/config references; it may contain prompt-like operator content. Credentials are not a declared field, but the envelope is stored verbatim. | No automatic cleanup found. Reset with the project event store while stopped. |
38
- | Same `run-events.db` — `run_state` | Materialized folded state JSON plus last event sequence for each run. `plugins/kxm/src/runtime-store.ts:631` | KXM runtime projection persistence. | Can repeat sensitive data derived from event payloads, assignments, evidence and outcomes; no generic redaction at storage. | No automatic cleanup found. Reset with the project event store while stopped. |
39
- | Same `run-events.db` — `attempt_capabilities` | Attempt/run/assignment/step/producer bindings, capability hash and issued/settled/revoked state. `plugins/kxm/src/runtime-store.ts:636` | KXM engine capability issuance and settlement. | Stores capability **hashes**, not an evident raw bearer credential. Operational authorization metadata is sensitive. | State is settled/revoked in place; no row-retention cleanup found. Reset with the project event store while stopped. |
40
- | Same `run-events.db` — `gate_attempts` | Gate identity/type/expected result, assignment/effect/step identities, definition/registry/plan hashes, control-project key, producer and intent-event linkage. `plugins/kxm/src/runtime-store.ts:646` | KXM gate engine. | No stdout/stderr bodies or credentials in the declared columns; hashes and control metadata may be sensitive. | No automatic cleanup found. Reset with the project event store while stopped. |
41
- | Same `run-events.db` — `gate_observations` | Process outcome metadata: spawned/PID/exit/signal/stop/error state, stdout/stderr SHA-256, byte/completeness counts, checked/failed counts, elapsed time and event linkage. `plugins/kxm/src/runtime-store.ts:668` | KXM gate executor/recorder. | Stores hashes and sizes, **not stdout/stderr bodies** in this table. Process/error metadata can still be sensitive. | No automatic cleanup found. Reset with the project event store while stopped. |
42
- | Same `run-events.db` — `gate_evidence` | Settled gate evidence identity, attempt/observation/run/step/assignment/effect bindings, optional evidence key, expected and actual outcome, event linkage and content hash. `plugins/kxm/src/runtime-store.ts:703` | KXM gate settlement code. | Evidence identity/outcome and hashes, not an evident raw evidence body in this table. Related event payloads may contain more detail. | No automatic cleanup found. Reset with the project event store while stopped. |
43
- | Same `run-events.db` — `drive_receipts` | Serialized final drive receipt plus run/project IDs, opened/last sequence, close time and schema. Receipt includes runtime/mode, log hash, settlement/handoff/error, budget and producer state. Added by schema migration 3→4. `plugins/kxm/src/runtime-store.ts:723` | KXM run-drive close/receipt persistence. | May contain handoff/error detail and operational metadata; not credentials by schema. No generic redaction at insert was established. | No automatic cleanup found. Reset with the project event store while stopped. |
44
- | `run-events.db.run-prompts.json` | Map of run ID to the **full accepted KXM prompt**; the event DB stores only its SHA-256. `plugins/kxm/src/runtime-store.ts:778` | `KxmRunEventStore.putRunPrompt`. | **Yes: raw prompt content.** Created with mode `0600`. No redaction is applied before writing. | No per-run deletion or retention path found. Stop the runtime and delete it together with its matching `run-events.db`; deleting only the sidecar makes historical prompt retrieval incomplete. |
45
- | SQLite `-wal` and `-shm` sidecars for all databases | SQLite write-ahead-log pages and shared-memory coordination; WAL can temporarily contain prior/current copies of any table data. WAL mode is explicitly enabled. `plugins/kxm/src/database.ts:137` | SQLite. | Same sensitivity as the corresponding DB, including message bodies, prompts and evidence. DB file creation mode is not explicitly chmod’d by `openDatabase`, so the exact live DB/WAL mode is **unknown** and depends on SQLite/OS/umask; backups/restores are chmod `0600`. | Stop all writers and remove DB, `-wal`, and `-shm` together. Never wipe only the main DB while a WAL remains. |
46
- | `external_effects` in the DB path supplied to `ExternalEffectsLedger` | Idempotency receipt for an external mutation: effect/run/step/attempt IDs, action kind, target reference, status, request payload hash, arbitrary receipt JSON, execution/heartbeat/completion times. Its compatibility migration attempts to add `last_heartbeat_at`. `plugins/kxm/src/external-effects.ts:117` | External-effect claim/heartbeat/commit/abort code. | `receipt_payload` is arbitrary JSON and is stored without redaction; it could contain remote IDs, URLs, errors or accidentally credentials. The original request payload is initially stored as JSON despite the field name becoming a receipt on completion. | Stale in-flight leases can be reclaimed after 300 seconds, but that updates the row rather than deleting it. No row-retention cleanup found. The constructor defaults to `:memory:` and no production file instantiation was found in the searched code, so its persistent file location/integration is **unknown**. If file-backed, close all ledger users before deleting that DB and sidecars. |
47
- | `.kxm/state/hub.pid` | Managed-process claim: schema version, wrapper PID, best-effort server child PID, role, start time and control filename. `scripts/kxm-hub.mjs:155` | Hub wrapper. | No secrets. Reveals process IDs and start time. Created exclusively at `0600`; subsequent rewrite does not reset mode, so a normally created file remains `0600`. | Removed by the wrapper on normal exit; stale valid claims are reclaimed after process liveness checks. Use `kxm hub stop`; manual removal is safe only after verifying both wrapper and recorded server child are not running. |
48
- | `.kxm/state/hub.stop` | Short-lived shutdown request containing the matching hub start time and request time. `plugins/kxm/src/cli/hub.ts:312` | `kxm hub stop`; consumed by the wrapper. | No secrets; process-control metadata only. Written `0600`. | Removed by the wrapper when consumed; startup also removes stale `hub.stop`. Do not use deletion as a substitute for stopping the hub. |
49
- | User-state `hub-env.json` — normally outside project `.kxm/state` | Schema/version and creation time plus raw `KXM_AUTH_TOKEN` and project-to-token map from `KXM_PROJECT_TOKENS`. Platform root is `KXM_STATE_HOME`, macOS Application Support, Windows LocalAppData, or XDG/`~/.local/state`. `plugins/kxm/src/hub-env.ts:23` | Hub startup credential resolver; explicit environment values win and can be persisted, otherwise an admin token is generated and persisted. | **Yes: this is the primary raw hub credential file.** Written through a `0600` temporary file and renamed. On POSIX, intended mode is `0600`; Windows does not provide equivalent POSIX-mode semantics. | No automatic expiry/rotation cleanup. Stop hub/workers first. Deleting it resets persisted hub credentials; the next start generates a new admin token unless explicit env credentials are supplied. Existing clients/workers using the old token will fail until reconfigured. |
50
- | `.kxm/logs/kxm-hub.jsonl` and rotated `.1`–`.3` files | Structured hub lifecycle, request/outcome and operational events. Default rotation is 10 MiB with three rotated files. `plugins/kxm/src/server.ts:16` · `plugins/kxm/src/logger.ts:44` | Hub structured logger. | Values are recursively redacted by sensitive key name and `redactSecrets` patterns before append. It should not intentionally contain credentials or message bodies, but pattern redaction is not a proof against every secret format. Newly created logs use `0600`; an existing file’s mode is not corrected. | Size-based rotation only; oldest rotated file is deleted. Safe to delete old rotated files while running, but deleting/renaming the active file while the process writes is platform-dependent and can lose logs. Prefer stopping the hub before a complete log wipe. |
51
- | `.kxm/logs/hub-autostart.log` | Hub wrapper stdout/stderr during extension autostart, including startup diagnostics and paths. `plugins/kxm/src/hub-autostart.ts:158` | Extension autostart spawner and hub wrapper/server standard streams. | Log tails are redacted when displayed, but the file descriptor receives raw stdout/stderr. Current startup output avoids printing token values, but future/raw errors could be sensitive. `openSync(..., "a")` supplies no explicit mode, so file mode is **unknown**/OS-umask-dependent. No rotation was found. | No automatic cleanup found. Prefer stopping the hub before deleting the active file; otherwise delete only when no autostarted process still has it open. |
52
- | `.kxm/assets/retrospectives/<runId>.json` and `.md` | Terminal workflow retrospective: run/stage outcomes, journal-derived proposed improvements, metrics, and immutable evidence provenance/hashes; prompt and reply bodies are explicitly excluded. `plugins/kxm/src/retrospective.ts:385` | Hub when a workflow reaches `completed` or `failed`. `plugins/kxm/src/hub.ts:458` | Redaction is applied to retrospective summaries/evidence during construction; bodies are excluded. Still contains project/run metadata and operational findings. Files are created `0600`. | No automatic retention/deletion found. These are independent of SQLite retention, so purging a workflow run does not remove its retrospective. Safe to remove completed retrospective files while the hub is running if no reader requires them; stopping first is safer for a total reset. |
53
-
54
- **Are message bodies stored?** Yes. Both request content and reply content are persisted in the `messages.record` JSON. Workflow coordinator messages also persist the rendered workflow prompt, which can include selected webhook payload values.
55
-
56
- **Are API keys or tokens stored in the DB, or only in environment/`0600` files?** Hub authentication and project tokens are intentionally stored raw in user-state `hub-env.json`, not in the reviewed hub tables. The KXM supervisor DB stores a token hash. However, SQLite is **not guaranteed secret-free**: arbitrary message bodies, prompts, event payloads, command results, workflow evidence/journal fields and external-effect receipts are stored without universal redaction and can contain credentials if a caller includes them.
57
-
58
- **Are webhook signatures stored?** No storage path was found for the received `X-Hub-Signature[-256]` value. It is read, compared with a computed HMAC, and discarded. Workflow webhook secrets come from workflow configuration/environment; the definition hash explicitly removes `secret` and `signalSecret`. The DB stores delivery IDs, payload hashes, signal results/evidence, and possibly payload-derived rendered prompt content—not the signature itself. `plugins/kxm/src/hub.ts:796`
59
-
60
- **Is evidence/journal content stored?** Yes. Legacy workflow evidence maps, signal summaries, journal summaries/details/evidence lists, KXM event payloads, command results, run state, gate metadata/hashes and drive receipts are durable. Some derived outputs are redacted, but workflow evidence and journal storage do not have a universal redaction boundary.
61
-
62
- **How does redaction apply before storage?** `redact.ts` recognizes selected OpenAI/Anthropic/GitHub/Slack/Google bearer-token formats, named token environment assignments, and any bare 64-hex string. `plugins/kxm/src/redact.ts:1` It is applied to structured logs and context summaries/source references, plus selected retrospective and diagnostic output. It is **not** automatically applied by the generic SQLite writers for messages, workflow runs/journals, KXM events/commands/plans/state/prompts, or external-effect receipts. A redacted field can still contain an unrecognized secret format, while the blanket 64-hex rule can also redact nonsecret hashes.
63
-
64
- **How do I wipe/reset data?** First run `kxm hub stop` and stop the KXM runtime/workers. For peer/workflow/context data, remove `.kxm/state/kxm.db`, `kxm.db-wal`, and `kxm.db-shm`. For KXM registration and runs, remove the user-state `runtime/registry.db` plus its sidecars and the relevant `runtime/projects/<projectKey>/` directories, including `run-events.db`, its sidecars and `.run-prompts.json`. Remove `.kxm/logs/` for logs and `.kxm/assets/retrospectives/` for exported retrospectives. Remove user-state `hub-env.json` only when intentionally rotating/resetting hub credentials. `hub.pid` and `hub.stop` are process-control files, not data-reset targets; let `kxm hub stop` and normal shutdown clean them. Direct DB/table edits are unsupported, and deleting live SQLite files is unsafe.