@kontextmind/kxm 0.7.94 → 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 +2 -2
  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 -293
  140. package/docs/webhook-workflows.md +0 -240
@@ -0,0 +1,262 @@
1
+ # Architecture
2
+
3
+ KXM connects coding agents in different harnesses through a durable [hub](../glossary.md#hub) and runs reviewed workflows on your machine through the [Runtime](../glossary.md#runtime). This page explains what each component does, how the pieces fit together, and what the system does not guarantee. Read it before you deploy KXM for a team or build on its interfaces.
4
+
5
+ ## The system at a glance
6
+
7
+ The diagram shows the three client surfaces, the two local services, and what crosses the loopback boundary.
8
+
9
+ ```mermaid
10
+ flowchart LR
11
+ subgraph Clients["Agents and operator"]
12
+ CC["Claude Code<br/>plugin: MCP stdio, channel, SessionStart hook"]
13
+ PI["Pi<br/>extension and skills"]
14
+ CLI["kxm CLI<br/>operator"]
15
+ end
16
+ subgraph Machine["Your machine: loopback by default"]
17
+ HUB[("KXM hub<br/>HTTP and SSE, SQLite kxm.db")]
18
+ RT["Runtime supervisor<br/>runs, event store, outbox"]
19
+ end
20
+ GIT[["Git repository<br/>.kxm/*.yaml"]]
21
+ EXT["Webhooks and CI<br/>signed starts and callbacks"]
22
+ CC -->|"MCP tools, SSE"| HUB
23
+ PI -->|"HTTP, SSE"| HUB
24
+ CLI -->|"admin and project APIs"| HUB
25
+ EXT -->|"HMAC-signed"| HUB
26
+ CLI -->|"kxm run, kxm runs"| RT
27
+ RT -->|"sync events, outbound only"| HUB
28
+ GIT -.->|"reviewed config"| CLI
29
+ GIT -.->|"pinned per run"| RT
30
+ ```
31
+
32
+ KXM has two planes:
33
+
34
+ - The **hub coordinates.** It authenticates agents, stores their messages, runs signed webhook workflows, keeps the journal and context, grants leases, and receives Runtime sync events. It never runs a model.
35
+ - The **Runtime executes.** It owns event-sourced runs of `kxm.workflow.v1` workflows on one machine, drives their steps through harnesses, and works with or without a hub.
36
+
37
+ ## What KXM is and is not
38
+
39
+ KXM is:
40
+
41
+ - a durable request/reply layer between agents in Pi, Claude Code, and other harnesses, with discovery by name and declared purpose;
42
+ - a workflow engine with typed steps, gates, budgets, and receipts. The Runtime schedules each run's steps and queues runs behind a per-project limit (`limits.maxConcurrentRuns`, default 1);
43
+ - a provenance and learning layer: hub-verified peer evidence, a structured journal, role-aware context, and governed memory and skills.
44
+
45
+ KXM is not a sandbox, a distributed system, an exactly-once executor, a planner that splits tasks or picks peers for you, or a shared model context. Agents exchange bounded messages, never conversation histories. [Limits and trade-offs](#limits-and-trade-offs) covers the boundaries that matter in production.
46
+
47
+ ## The hub
48
+
49
+ The hub is one Node.js process that serves HTTP and server-sent events (SSE) and writes everything to one SQLite database, `.kxm/state/kxm.db` by default. It binds `127.0.0.1:7331` unless you set `KXM_HOST` and `KXM_PORT`, and it refuses to bind beyond loopback without an admin token. SQLite is the source of truth after a restart; in-memory maps are only the live working set.
50
+
51
+ | Subsystem | What it does | Read more |
52
+ |---|---|---|
53
+ | Projects | The authentication and discovery namespace; agents see only peers in their own project | [Trust model](trust-model.md#project-isolation) |
54
+ | Agents and presence | Registration returns a rotating agent key; presence (`online`, `stale`, `offline`) comes from the hub's clock | [Peer messaging](../guides/peer-messaging.md) |
55
+ | Messages | Durable request/reply with TTL, cancellation, idempotency keys, and fanout to one to three peers | [Message lifecycle](#message-lifecycle) |
56
+ | Webhook workflows | Signed webhooks start runs with ordered stages, evidence checkpoints, waits, and signed callbacks | [Webhook workflows](../guides/webhook-workflows.md) |
57
+ | Journal | Ten categories of run knowledge, from `plan` to `skill-candidate`; a retrospective for every finished run | [Continuous improvement](../guides/continuous-improvement.md) |
58
+ | Context OS | Context items, temporal state, recall, episodes, a compiled wiki, and role-aware packets | [Context and memory](../guides/context-and-memory.md) |
59
+ | Leases | Fenced, project-scoped leases timed by the hub's clock | [HTTP API](../reference/http-api.md) |
60
+ | Sync ingest | Accepts Runtime presence and sync events, each `{project, run, sequence}` exactly once | [Runtime sync](../operations/runtime-sync.md) |
61
+ | Operations stream | Admin-only, metadata-only snapshot and SSE for `kxm dash`, plus Prometheus `/metrics` | [Monitoring](../operations/monitoring.md) |
62
+
63
+ A lease holder receives a fencing token that increments only when another holder takes over an expired lease, so a stale holder can be refused before it commits a shared change. The lease routes are available to any agent in the project; the Runtime does not take leases on its own yet.
64
+
65
+ ### Message lifecycle
66
+
67
+ A message is a durable request with one recipient and at most one reply; the diagram shows every state the hub sets.
68
+
69
+ ```mermaid
70
+ stateDiagram-v2
71
+ state "error (reserved)" as err
72
+ [*] --> queued: sender posts
73
+ queued --> delivered: recipient acknowledges
74
+ queued --> replied: recipient replies
75
+ delivered --> replied: recipient replies
76
+ queued --> cancelled: sender cancels
77
+ delivered --> cancelled: sender cancels
78
+ queued --> expired: TTL elapses
79
+ delivered --> expired: TTL elapses
80
+ replied --> [*]
81
+ cancelled --> [*]
82
+ expired --> [*]
83
+ note right of queued
84
+ Stored in SQLite. Pushed again on every
85
+ reconnect until the recipient acknowledges it.
86
+ end note
87
+ classDef reserved stroke-dasharray:5 5
88
+ class err reserved
89
+ ```
90
+
91
+ - The sender gets the message ID at once. The recipient may reply straight from `queued` without acknowledging first.
92
+ - `error` is declared in the protocol, but the hub never sets it. Treat it as reserved.
93
+ - Open messages survive a hub restart. When an agent reconnects under the same project and name, the hub rotates its key and pushes every `queued` message again with its original ID. A `delivered` message is not pushed again; it stays open until a reply, cancellation, or expiry. Clients suppress a second turn for an ID they already handle.
94
+ - An idempotency key deduplicates an exact retry by the same sender. It does not stop the recipient from repeating a side effect, so handlers must be safe to repeat.
95
+ - The default TTL is 24 hours (at most 7 days). Terminal messages are purged after the retention window, 7 days by default.
96
+ - If a workflow coordinator's prompt expires before its run finishes, the run fails.
97
+
98
+ ### Hub workflow run lifecycle
99
+
100
+ A signed webhook creates a run and its coordinator message in one request; the diagram shows how the run moves between its four states.
101
+
102
+ ```mermaid
103
+ stateDiagram-v2
104
+ [*] --> running: signed webhook
105
+ running --> running: warning or failed retries, passed opens next stage
106
+ running --> waiting: coordinator waits, or audit escalation
107
+ waiting --> running: signed signal, more work needed
108
+ running --> completed: last stage passes
109
+ waiting --> completed: signed signal passes last stage
110
+ running --> failed: maxAttempts or budget used up, early reply, prompt expired
111
+ waiting --> failed: deadline passes, or signal exhausts attempts
112
+ completed --> [*]
113
+ failed --> [*]
114
+ ```
115
+
116
+ - Stages run in order. A `warning` or `failed` checkpoint retries the same stage until its `maxAttempts` is used up. Declared `on` outcomes add typed transitions, including back-edges, each bounded by per-edge, per-stage, and global `maxTransitions` budgets.
117
+ - A coordinator reply while the run is `running` fails the run, because required work was abandoned.
118
+ - A wait releases the coordinator: its reply while `waiting` is expected. A signed callback resumes the stage and sends a fresh message when more work remains. The deadline is 1 second to 30 days (default 24 hours); when it passes, the run fails and the coordinator is told.
119
+ - After `autoResumeLimit` failed attempts, a stage escalates to an `audit_escalation` wait for an operator ruling.
120
+ - Every run records a secret-free `definitionHash`, and every finished run exports a retrospective.
121
+
122
+ Peer-reply evidence, quorum, and degradation have their own guide: [Provenance gates](../guides/provenance-gates.md).
123
+
124
+ ## The Runtime
125
+
126
+ The Runtime is one supervisor process per OS user and machine, and it can host many projects. `kxm run` and `kxm runs` start it on demand; `kxm runtime start` starts it explicitly. It listens on an ephemeral `127.0.0.1` port, and every call except its health check needs the bearer token from a `0600` file in the user state root.
127
+
128
+ A run moves through five phases:
129
+
130
+ 1. `kxm run <workflow> [prompt]` validates the project, records the run as `created`, and pins the configuration, memory, executor-policy, and tool-policy revisions. No hub is involved.
131
+ 2. `kxm runs drive <runId>` pins the compiled run plan (`preparing`) and then executes steps in order (`running`). With `--simulated`, a model-free producer answers the agent steps while gate steps still run their commands; without it, the drive is live.
132
+ 3. Every change is an event, appended to the project's event store in one transaction with an outbox row. State is always a replay of those events, and a stored projection that disagrees with the log is refused.
133
+ 4. When a drive stops, it writes a drive receipt: terminal, handoff, or unsettled. `kxm runs status` and `kxm runs receipt` show it and whether it verifies.
134
+ 5. The supervisor pushes outbox rows to the bound hub. Without a hub, rows wait locally until one is bound.
135
+
136
+ Steps are `agent`, `moa`, `approval`, `wait`, or `gate`. The first four go to a producer through an assignment and an attempt; each attempt gets a capability secret that is stored only as a hash. `approval` and `wait` steps go to the first agent in the step's `assignments.allowedAgents`, else to the agent whose ID is literally `coordinator`, not to the workflow's `coordinator:` value. Gate steps run entries from `.kxm/gates.yaml` as an argument list without a shell, and keep only hashes and sizes of their output.
137
+
138
+ A live drive runs each agent's harness as a one-shot, read-only process. When a step needs something this build does not execute, such as write access in a live drive, the drive stops with a handoff (`run_handoff_required`) instead of guessing. The [configuration reference](../reference/config-reference.md#steps-the-runtime-does-not-execute-yet) lists every such case.
139
+
140
+ A dispatched agent also receives the project's committed memory and hash-verified promoted skills, but only when those files are committed, clean, and match the run's pinned memory revision. Otherwise dispatch continues without them and records a gap. Dispatch reads nothing from the hub.
141
+
142
+ ### Runtime run lifecycle
143
+
144
+ The diagram shows the run states the event fold accepts in this build.
145
+
146
+ ```mermaid
147
+ stateDiagram-v2
148
+ [*] --> created: kxm run
149
+ created --> preparing: first drive pins the plan
150
+ preparing --> running: steps start
151
+ running --> completed: terminal transition
152
+ running --> failed: failure outcome or budget exhausted
153
+ running --> cancelled: workflow ends as cancelled
154
+ running --> cancelling: cancel or run-duration budget
155
+ cancelling --> cancelled: attempts drained
156
+ running --> blocked_uncertain: gate outcome cannot be proven
157
+ blocked_uncertain --> running: retry or unblock
158
+ blocked_uncertain --> failed: fail
159
+ blocked_uncertain --> cancelling: cancel
160
+ completed --> [*]
161
+ failed --> [*]
162
+ cancelled --> [*]
163
+ ```
164
+
165
+ A run can also be cancelled or fail before it reaches `running`, and the fold permits `cancelling → failed`. There is no `waiting` state: the contracts specify one, but the fold refuses it, so a Runtime run never parks the way a hub workflow run does. You resolve `blocked_uncertain` with `kxm gate signal <runId> … --recovery-action retry|unblock|fail|cancel`.
166
+
167
+ Inside a run, each object has its own linear lifecycle:
168
+
169
+ | Object | States in this build |
170
+ |---|---|
171
+ | Step | `pending` → `preparing` → `running` → `passed`, `failed`, or `cancelled` |
172
+ | Assignment | `created` → `accepted` → `dispatched` → `executing` → `result_recorded` → `terminal` |
173
+ | Attempt | `created` → `starting` → `executing` → `settling` → `terminal`, with result class `outcome`, `outcome_unknown`, `producer_rejected`, or `cancelled` |
174
+
175
+ > [!NOTE]
176
+ > [Durable lifecycles](../contracts/lifecycles.md) specifies the target lifecycle, including `waiting`, `skipped`, `retry_pending`, `reattaching`, and `connection_lost`. This build does not reach those states yet.
177
+
178
+ ## The clients
179
+
180
+ ### The kxm CLI
181
+
182
+ The CLI is the operator's tool. It starts and binds the hub (`kxm hub`), creates and drives runs (`kxm run`, `kxm runs`), manages the supervisor (`kxm runtime`), sets up and reviews projects (`kxm init`, `kxm trust`), sends peer requests (`kxm peer`), operates workflows and gates (`kxm workflow`, `kxm gate`), and backs up and restores SQLite stores (`kxm backup`, `kxm restore`). The [CLI reference](../reference/cli-reference.md) covers every command.
183
+
184
+ ### The Pi extension
185
+
186
+ The extension loads into Pi from the KXM package. It registers the 19 KXM tools, the `/kxm` and `/workflow` commands, and status widgets, and it turns inbound requests into Pi turns. It can start a hub in the background (`hub.autoStart: background`). `kxm agent worker` runs Pi as a long-lived supervised worker, optionally with one Pi session per workflow run. See [Pi workers](../guides/pi-workers.md).
187
+
188
+ ### The Claude Code plugin
189
+
190
+ The plugin has four parts:
191
+
192
+ - an **MCP stdio server** that exposes the same 19 tools;
193
+ - an optional **channel** that pushes peer requests into the session, with `kxm_inbox` and `kxm_reply` as the pull alternative;
194
+ - a **SessionStart hook**, a bundled read-only Node script that prints a short KXM status and the project memory brief, and needs no `kxm` on `PATH`;
195
+ - the bundled **skills**.
196
+
197
+ The plugin never falls back to the admin token. See the [plugin README](../../plugins/kxm/README.md) and [Quick start with Claude Code](../start/quickstart-claude-code.md).
198
+
199
+ ### Agent Skills
200
+
201
+ The package ships a directory of `SKILL.md` suites that Pi and Claude Code both load: the `kxm-*` skills that teach each command group, browser-automation skills, and skills for the separate KontextMind knowledge plane. See [Agent Skills](../guides/agent-skills.md).
202
+
203
+ ### Dash and Studio
204
+
205
+ `kxm dash` draws live terminal screens (agents, tasks, workflows, plans, inbox, processes, and spend, which is always empty today) from the admin-only operations stream, a presence-only fallback, and a read-only snapshot of `kxm.db`. Treat it as an observer: its action keys `a`, `r`, `s` and `c` post to hub routes that do not exist, so they change nothing even though the status line reports success, and `d` creates a git branch and worktree.
206
+
207
+ `kxm studio layout` renders a workflow as DAG, stepper, and swimlane JSON, and `kxm studio serve` hosts a local viewer on `127.0.0.1:4242`. The Studio mutation endpoint is not wired to commands: it acknowledges requests without running them.
208
+
209
+ ## Configuration is reviewed Git YAML
210
+
211
+ Project behavior lives in Git under `.kxm/`: `project.yaml`, `agents/`, `models/`, `workflows/`, `gates.yaml`, `roles/`, `routes.yaml`, `memory/`, and `skills/`. The project bundle (`project.yaml`, `agents/`, `models/`, `workflows/`, and `gates.yaml`) is restricted YAML checked against a JSON Schema. `routes.yaml`, `roles/`, and the front matter in `memory/` and `skills/` are parsed as ordinary YAML with their own checks, and a live drive re-reads an agent file the same way to resolve its route. Git review is the activation boundary:
212
+
213
+ - Every run pins revision hashes of the project bundle, memory, executor policy, and tool policy. An edit affects only later runs, and a run whose pinned revisions drift is refused.
214
+ - `kxm trust diff` prints a structured permission diff against a base revision (default `HEAD`). `kxm trust check` exits non-zero when the change expands permissions. Neither covers `routes.yaml`, `roles/`, `roster.yaml`, or `prices.yaml`, so admitting a route is not flagged.
215
+ - Legacy `.kxm/config/*.json` files are refused, never converted.
216
+
217
+ Webhook workflow definitions are separate JSON that the hub loads at start, with secrets named by environment variable. Personal settings merge built-in defaults, then `~/.config/kxm/config.yaml`, then the project's `.kxm/config.yaml`. See the [configuration file reference](../reference/config-reference.md) and [Configuration](../reference/configuration.md).
218
+
219
+ ## Harness routing
220
+
221
+ A route is a harness plus a model. In a live drive, the Runtime resolves each agent's harness (its `harness`, else the project's `defaultHarness`) and model, refuses any `provider/model` that `.kxm/routes.yaml` does not admit, and checks the role roster when one exists. It then probes the harness's login and starts a one-shot process. A refusal never falls back to another route.
222
+
223
+ The rule is to run a vendor's model in that vendor's native harness, never through Pi. The Pi native-vendor brake enforces it in two places: the probe each producer runs before it starts a harness, and `kxm agent worker`, which checks the primary model and every fallback before Pi starts. It refuses a native vendor's model whether the id names the vendor directly, through that vendor's own Pi provider, or behind an aggregator.
224
+
225
+ Admission is the second layer. Some cases are still operator policy, among them reseller ids that name no vendor and whether Google work runs through `agy` or the `antigravity` Pi provider; see [where the code is looser than the rules](../reference/harness-routing.md#where-the-code-is-looser-than-the-rules). [Harness routing](../reference/harness-routing.md) explains how to choose a route and confirm which one ran.
226
+
227
+ ## Packaging
228
+
229
+ One npm package, `@kontextmind/kxm`, carries every surface. It needs Node.js 22.19 or later on the 22 line, or 24 and later. It has no native dependencies: SQLite comes from Node's built-in `node:sqlite`, or from `bun:sqlite` inside Pi. The plugin does not install the CLI, so install both when you want Claude Code and the operator commands on one machine.
230
+
231
+ | Surface | What ships | Install guide |
232
+ |---|---|---|
233
+ | npm package | The `kxm` CLI, prebuilt hub, Runtime supervisor, MCP server and hook bundles, wrapper scripts, schemas, docs, and examples | [Install](../start/install.md) |
234
+ | Pi package | The same package: its `pi` manifest loads the extension and the skills directory | [Quick start with Pi](../start/quickstart-pi.md) |
235
+ | Claude Code plugin | `plugins/kxm` from the `kxm` marketplace: MCP server, channel, SessionStart hook, and skills | [Quick start with Claude Code](../start/quickstart-claude-code.md) |
236
+
237
+ ## Why KXM is built this way
238
+
239
+ - **Execution stays local.** A hub outage never stops a run, and repositories and provider credentials never collect in one service. The original decision is [ADR-001](../contracts/architecture.md).
240
+ - **SQLite for every store.** The workload is many small writes owned by one process. See [ADR-0003](../adr/ADR-0003-sqlite-only-store.md).
241
+ - **Git review activates behavior.** Runs pin revisions, and learned content cannot activate itself; memory and skills reach agents only through reviewed files and governed promotion.
242
+ - **Browser identity stays at the edge.** A hosted hub sits behind a proxy and a portal and never interprets browser identity. See [ADR-0004](../adr/ADR-0004-edge-identity-authentik.md).
243
+ - **Stores refuse old schemas.** An older or newer store is refused, never migrated in place. See [Data and storage](data-and-storage.md#schema-versions-refuse-do-not-migrate).
244
+
245
+ ## Limits and trade-offs
246
+
247
+ - **Single node.** One hub process owns one SQLite file, and one Runtime owns each machine's runs. Do not load-balance hubs.
248
+ - **At-least-once.** A crash after a side effect but before the reply or settlement can repeat work. Use idempotency keys and delivery IDs, and design every handler to be safe to repeat.
249
+ - **Not a sandbox.** Tool allowlists, roles, session isolation, and project tokens prevent mistakes, not a hostile process under the same OS user. See the [trust model](trust-model.md#kxm-is-not-a-sandbox).
250
+ - **Quorum proves routing, not truth.** A verified peer reply proves which registered identity answered in which run, stage, and attempt. It does not prove the answer is correct, independent, or approved by a person.
251
+ - **The Runtime does not run everything yet.** Live drives are read-only, runs have no `waiting` state, and unsupported steps hand off. A drive receipt's `logHash` covers event IDs and sequence numbers, not payloads, and receipts are not signed.
252
+ - **Retention is short on the hub.** Finished hub runs and their journal are purged after 7 days, which also ends webhook deduplication for them. Runtime event stores keep everything.
253
+ - **Some reads are local.** `kxm workflow list` and `get`, `kxm session brief`, the SessionStart hook, and part of `kxm dash` read `kxm.db` directly, so they see hub runs only on the hub's machine. The session brief and the hook also read this machine's Runtime runs, and report what they found as `source`: `legacy`, `runtime`, or `both`.
254
+
255
+ ## Related
256
+
257
+ - [Trust model](trust-model.md)
258
+ - [Data and storage](data-and-storage.md)
259
+ - [Architecture decision records](../adr/README.md)
260
+ - [Durable lifecycles](../contracts/lifecycles.md)
261
+ - [Deploy KXM](../operations/deploy.md)
262
+ - [Glossary](../glossary.md)
@@ -0,0 +1,194 @@
1
+ # Data and storage
2
+
3
+ KXM keeps its state in a few SQLite databases and a handful of files, split between your project checkout and a per-user state root. This page explains what each store holds, where it lives, what is kept as a hash instead of as content, how long data stays, and why KXM refuses old stores instead of migrating them. Read it before you back up, wipe, or audit a KXM installation.
4
+
5
+ ## Where data lives
6
+
7
+ The diagram shows which process owns each store and which root it lives under.
8
+
9
+ ```mermaid
10
+ flowchart LR
11
+ subgraph Project["Project checkout"]
12
+ CFG[".kxm/*.yaml<br/>reviewed config in Git"]
13
+ HDB[(".kxm/state/kxm.db<br/>hub store")]
14
+ LOGS[".kxm/logs<br/>hub and worker logs"]
15
+ RETRO[".kxm/assets/retrospectives"]
16
+ end
17
+ subgraph StateRoot["User state root"]
18
+ ENV["hub-env.json<br/>hub credentials"]
19
+ REG[("runtime/registry.db")]
20
+ EVT[("run-events.db per project<br/>+ run-prompts.json")]
21
+ end
22
+ HUB["KXM hub"] -->|"writes"| HDB
23
+ HUB -->|"writes"| LOGS
24
+ HUB -->|"exports"| RETRO
25
+ ENV -.->|"credentials"| HUB
26
+ RT["Runtime supervisor"] -->|"writes"| REG
27
+ RT -->|"writes"| EVT
28
+ CFG -.->|"read at run start"| RT
29
+ RT -->|"sync events"| HUB
30
+ ```
31
+
32
+ KXM uses three locations:
33
+
34
+ - **The project workspace**, `.kxm/` at the project root. Reviewed configuration is tracked in Git. `state/`, `logs/`, and `assets/` hold what the hub and workers write. `KXM_WORKSPACE_DIR`, `KXM_STATE_DIR`, `KXM_LOGS_DIR`, `KXM_ASSETS_DIR`, and `KXM_DATA_PATH` move those parts; configuration always stays under `<project root>/.kxm/`.
35
+ - **The user state root**, for machine-level state that must never be committed.
36
+ - **The user configuration directory**, `KXM_USER_CONFIG_DIR` (default `~/.config/kxm`), for personal `config.yaml`, global roles and workflows, and the local session token.
37
+
38
+ The user state root is `KXM_STATE_HOME` when set; it must be an absolute path. Otherwise it depends on the operating system:
39
+
40
+ | Operating system | User state root |
41
+ |---|---|
42
+ | macOS | `~/Library/Application Support/KXM` |
43
+ | Linux | `$XDG_STATE_HOME/kxm`, default `~/.local/state/kxm` |
44
+ | Windows | `%LOCALAPPDATA%\KXM` |
45
+
46
+ The hub writes its database under the workspace of the directory it starts in. Start it from the project root so that `kxm.db` lands in that project's `.kxm/state/`.
47
+
48
+ ## The hub store
49
+
50
+ The hub store is `.kxm/state/kxm.db` (or `KXM_DATA_PATH`). Like every KXM store, it records its schema version and refuses any other; see [Schema versions: refuse, do not migrate](#schema-versions-refuse-do-not-migrate). It has ten `STRICT` tables:
51
+
52
+ | Table | What it holds | Sensitive content |
53
+ |---|---|---|
54
+ | `agents` | Agent ID, name, purpose, project, model, host label, timestamps, and the current agent key | Agent keys in plain text |
55
+ | `messages` | Each request and reply with routing metadata and any workflow context | Request and reply bodies, as sent |
56
+ | `consumer_cursors`, `agent_sequences` | Each agent's delivery position and next message sequence | None |
57
+ | `workflow_runs` | Hub workflow runs: stages, evidence, waits, signal receipts, transitions, verified peer snapshots, hashes | Evidence strings |
58
+ | `workflow_journal` | Journal entries with category, area, stage, and attempt | Summaries, details, and evidence |
59
+ | `context_items` | Context items and state proposals with provenance and validity | Summaries, pattern-redacted |
60
+ | `leases` | Fenced leases with holder and fencing token | None |
61
+ | `sync_events` | Runtime events the hub accepted, once per project, run, and sequence | Sync-safe summaries |
62
+ | `runtime_presence` | Runtime heartbeats per project | Host label |
63
+
64
+ A coordinator message holds the rendered workflow prompt, which can include fields from the webhook payload. The raw webhook body is not stored; the run keeps only its SHA-256.
65
+
66
+ Some readers open `kxm.db` directly and read-only: `kxm workflow list` and `get`, `kxm session brief`, the Claude Code SessionStart hook, and parts of `kxm dash`. They see hub runs only on the hub's machine. The session brief and the hook also open this machine's Runtime stores read-only, and report what they found as `source`: `runtime` or `both` when a Runtime store exists, otherwise `legacy`.
67
+
68
+ ## The Runtime stores
69
+
70
+ The Runtime keeps a registry for the machine and one event store for each project, all under `runtime/` in the user state root.
71
+
72
+ The **registry** is `runtime/registry.db`. Its `supervisor` table holds one row: the Runtime ID, process ID, port, a hash of the supervisor token, heartbeat, and state. Its `projects` table records each project's ID, canonical root path, project key, and home Runtime.
73
+
74
+ Each **event store** is `runtime/projects/<key>/run-events.db`. The key is the first 24 hex characters of the SHA-256 of the canonical project root. The store has 14 `STRICT` tables:
75
+
76
+ | Tables | What they hold |
77
+ |---|---|
78
+ | `runs`, `events`, `commands` | Each run with pinned revisions and a prompt hash; the append-only event log; idempotent command results |
79
+ | `run_plans`, `run_state` | The pinned compiled plan; the materialized projection |
80
+ | `attempt_capabilities` | Attempt bindings and the hash of each capability secret |
81
+ | `gate_attempts`, `gate_observations`, `gate_evidence` | Gate identity, process outcome with output hashes and sizes, and settled evidence |
82
+ | `drive_receipts` | The final receipt of each drive |
83
+ | `coordinators`, `intake_messages`, `project_controls` | Intake bindings, idempotent intake, and the project pause switch |
84
+ | `outbox` | One sync row per event, with its acknowledgement or refusal |
85
+
86
+ Gate rows are checked again every time the Runtime folds a run: their content hashes must recompute and match the events that name them, or the run is refused with a `gate_evidence_*` code such as `gate_evidence_hash_mismatch` or `gate_evidence_orphan`. A gate command that never starts fails its run with the reason `gate_start_failed`.
87
+
88
+ Next to each event store, `run-events.db.run-prompts.json` (`0600`) holds the **full prompt text** of every run. The `runs` table keeps only its hash, so the sidecar is the one place a prompt survives. Event payloads, command results, and run plans can also contain instructions, summaries, and evidence.
89
+
90
+ Every event commits in the same transaction as its outbox row. The supervisor pushes those rows to the bound hub, and a row the hub durably refuses stays parked until you run `kxm runtime sync-retry`. See [Runtime sync](../operations/runtime-sync.md).
91
+
92
+ ## Other files
93
+
94
+ | File | What it holds | Notes |
95
+ |---|---|---|
96
+ | `hub-env.json` (state root) | The raw admin token and project-token map | Written `0600` through a temporary file; the hub's primary credential file |
97
+ | `hub-binding.json` (state root) | This machine's hub URL and when it was bound | No credential |
98
+ | `runtime/supervisor.token` (state root) | The raw supervisor token | `0600`; the registry stores only its hash |
99
+ | `runtime/logs/kxm-runtime.jsonl` (state root) | The supervisor's structured log, including sync state changes | Rotates at 2 MiB |
100
+ | `session.token` (user configuration directory) | An unsigned local session token with a tool policy | `0600`; 24-hour default lifetime |
101
+ | `.kxm/state/hub.pid`, `hub.stop` | Hub process claim and stop request | Process control only; let `kxm hub stop` manage them |
102
+ | `.kxm/state/pi-sessions/<worker>/` | Pi conversation history for a supervised worker | At most `KXM_WORKER_MAX_RUN_SESSIONS` (default 128) run histories per worker |
103
+ | `.kxm/logs/kxm-hub.jsonl` | The hub's structured log, without message bodies | Rotates at 10 MiB and keeps three rotated files |
104
+ | `.kxm/logs/pi-agent-<worker>.log` | Raw Pi standard output and error | Can contain model and tool output verbatim |
105
+ | `.kxm/logs/telemetry.jsonl` | Result envelopes from gate commands | Read by `kxm improve` |
106
+ | `.kxm/assets/retrospectives/<runId>.json`, `.md` | Exported retrospectives of finished hub runs | `0600`; no message bodies |
107
+
108
+ Every SQLite database also has `-wal` and `-shm` sidecars while in use. The write-ahead log can hold copies of any recent row, so treat it as sensitively as the database.
109
+
110
+ ## What is stored, hashed, or never kept
111
+
112
+ **Stored as sent**, without encryption and without general redaction:
113
+
114
+ - message request and reply bodies, and rendered workflow prompts;
115
+ - workflow evidence and journal entries;
116
+ - agent keys, and the admin and project tokens in `hub-env.json`;
117
+ - Runtime prompts, event payloads, command results, and run plans;
118
+ - Pi session histories and raw Pi logs.
119
+
120
+ **Kept only as a hash:**
121
+
122
+ - the raw webhook body (`payloadHash`);
123
+ - the request and reply behind each verified peer snapshot, which therefore survives message purging;
124
+ - the Runtime prompt, in the event store's `runs` table (the sidecar keeps the text);
125
+ - attempt capability secrets and, in the registry, the supervisor token;
126
+ - gate command standard output and error, with their sizes;
127
+ - the workflow definition (`definitionHash`, computed without its secrets), and the reproduction oracle and plan hash of a hub run.
128
+
129
+ **Never persisted:** webhook signatures, which are checked and discarded, and workflow secrets, which stay in the environment variables that `secretEnv` and `signalSecretEnv` name.
130
+
131
+ ## Redaction
132
+
133
+ KXM redacts with known credential patterns, such as API keys, bearer tokens, and named token variables. It applies them to:
134
+
135
+ - the hub's structured log, which also redacts by key name;
136
+ - context item summaries and source references;
137
+ - retrospectives, ranked improvement signals, and some diagnostics;
138
+ - every Runtime event before it enters the outbox, together with the allowlist transform described in the [trust model](trust-model.md#redaction-and-what-stays-local).
139
+
140
+ Nothing redacts messages, hub workflow runs, the journal, or the Runtime's own stores at write time. Pattern redaction also misses unfamiliar secret formats, and its rule for 64-character hex strings masks ordinary SHA-256 digests too. Keep credentials out of prompts and evidence.
141
+
142
+ ## Retention
143
+
144
+ | Data | How long it stays |
145
+ |---|---|
146
+ | Terminal messages (`replied`, `cancelled`, `expired`) | `KXM_MESSAGE_RETENTION_MS` after they end; default 7 days |
147
+ | Finished hub workflow runs and their journal | 7 days after their last update; not configurable |
148
+ | Journal entries whose run is gone | 7 days |
149
+ | Superseded, rejected, or expired context items | 7 days after they end |
150
+ | Expired leases | 7 days past their deadline, so a fencing token never restarts |
151
+ | Agents, cursors, sequences, sync events, Runtime presence | Kept |
152
+ | Runtime registry and event stores | Kept; the event log is append-only |
153
+ | Retrospectives | Kept; purging a run does not remove them |
154
+
155
+ Purging a hub run also ends webhook delivery deduplication for it and removes the episodes derived from its journal. Purging superseded state limits `--as-of` queries to roughly the last 7 days.
156
+
157
+ ## Schema versions: refuse, do not migrate
158
+
159
+ Each database records its schema version in SQLite's `user_version`. When a process opens a store:
160
+
161
+ - a newer store fails with `runtime_schema_newer`;
162
+ - an older store fails with `runtime_schema_outdated`;
163
+ - a store with tables but no version fails with `runtime_schema_shape_invalid`.
164
+
165
+ KXM never upgrades a store in place, because the code would otherwise have to keep working against schema shapes it no longer tests. To cross a store version, stop the owner, back up if you need the history, delete the store with its `-wal` and `-shm` files, and let the owner recreate it: `kxm hub start` for `kxm.db`, and the Runtime for the registry and event stores. `kxm init` rebuilds no database. Legacy `.kxm/config/*.json` files are refused the same way.
166
+
167
+ Every store opens in WAL mode with a 5-second busy timeout, `synchronous=NORMAL`, and foreign keys on. A database or sidecar that is a symbolic link is refused. [ADR-0003](../adr/ADR-0003-sqlite-only-store.md) records why SQLite is the only store.
168
+
169
+ ## Reset a store
170
+
171
+ > [!CAUTION]
172
+ > Deleting a store erases its history for good. Back it up first if you might need it. `kxm backup` copies the hub store, but it does not find the Runtime stores in the user state root, so copy those with the Runtime stopped.
173
+
174
+ Stop every writer first, then delete each database together with its sidecars:
175
+
176
+ ```bash
177
+ kxm hub stop
178
+ kxm runtime stop
179
+ ```
180
+
181
+ - Hub messages, workflow runs, and context: `.kxm/state/kxm.db`, `kxm.db-wal`, and `kxm.db-shm`.
182
+ - Runtime runs for one project: `runtime/projects/<key>/` in the user state root, including `run-events.db`, its sidecars, and `run-events.db.run-prompts.json`.
183
+ - Runtime registration: `runtime/registry.db` and its sidecars. Deleting it alone leaves event stores that nothing points to.
184
+ - Hub credentials: `hub-env.json`, only when you intend to rotate them. The next `kxm hub start` generates a new admin token, and every client that used the old one fails until you reconfigure it.
185
+
186
+ Never delete a live database, and never delete only the main file while its `-wal` remains. [Back up and restore](../operations/backup-and-restore.md) covers `kxm backup` and `kxm restore`, and [Upgrade KXM](../operations/upgrade.md) covers version changes.
187
+
188
+ ## Related
189
+
190
+ - [Trust model](trust-model.md)
191
+ - [Architecture](architecture.md)
192
+ - [Back up and restore](../operations/backup-and-restore.md)
193
+ - [Configuration file reference](../reference/config-reference.md#workspace-layout-tracked-ignored-and-state)
194
+ - [ADR-0003: SQLite as the only store](../adr/ADR-0003-sqlite-only-store.md)
@@ -0,0 +1,152 @@
1
+ # Trust model
2
+
3
+ KXM decides who may do what with a small set of credentials, each scoped to one job. This page explains which credential proves what, who should hold it, and where each boundary stops, including the things KXM deliberately does not protect against. It is for operators who deploy a hub and for anyone reviewing KXM's security.
4
+
5
+ ## Who can reach what
6
+
7
+ The diagram shows each credential holder and the only endpoints that credential opens.
8
+
9
+ ```mermaid
10
+ flowchart LR
11
+ subgraph Holders
12
+ OP["Operator<br/>admin token"]
13
+ AG["Agents<br/>project token + agent key"]
14
+ RTS["Runtime supervisor<br/>project token"]
15
+ WH["Webhook sender<br/>start secret"]
16
+ CI["CI reporter<br/>signal secret"]
17
+ CLI["Local CLI<br/>supervisor token"]
18
+ end
19
+ subgraph Hub["KXM hub"]
20
+ ADMIN["Admin routes<br/>metrics, ops, degrade, promote"]
21
+ PROJ["Project routes<br/>register, presence, sync"]
22
+ AGENT["Agent routes<br/>messages, workflows, context, leases"]
23
+ START["Webhook start"]
24
+ SIGNAL["Run signal"]
25
+ end
26
+ RAPI["Runtime API<br/>127.0.0.1 only"]
27
+ OP -->|"bearer"| ADMIN
28
+ OP -.->|"only projects without a token"| PROJ
29
+ AG -->|"bearer"| PROJ
30
+ AG -->|"bearer + agent key"| AGENT
31
+ RTS -->|"bearer"| PROJ
32
+ WH -->|"HMAC-SHA256"| START
33
+ CI -->|"HMAC-SHA256"| SIGNAL
34
+ CLI -->|"bearer"| RAPI
35
+ ```
36
+
37
+ `/health` and `/ready` need no credential and are not rate limited. Everything else on the hub needs one of the credentials below.
38
+
39
+ ## Credentials
40
+
41
+ | Credential | Holder | Where it lives | What it opens |
42
+ |---|---|---|---|
43
+ | Admin token (`KXM_AUTH_TOKEN`) | The hub and a trusted operator terminal | The environment, else `hub-env.json` (`0600`) in the user state root | Admin routes; agent routes only for projects that have no project token |
44
+ | Project token (`KXM_PROJECT_TOKENS` entry) | Agents and the Runtime for that project | The hub's environment or `hub-env.json`; clients pass it as `KXM_AUTH_TOKEN` | Registration, Runtime presence, and sync events in that one project |
45
+ | Agent key | The hub and one registered client | Issued at registration, rotated at every reconnect, stored in `kxm.db` | Identity routes: messages, events, workflows, context, leases |
46
+ | Workflow start secret | The hub and the webhook sender | The variable named by the definition's `secretEnv` | Starting runs of that one definition |
47
+ | Workflow signal secret | The hub and the callback sender | The variable named by `signalSecretEnv`; falls back to the start secret | Signals for runs of that definition |
48
+ | Runtime supervisor token | The Runtime and local CLI processes | `runtime/supervisor.token` (`0600`); the registry keeps only its hash | The Runtime API on `127.0.0.1` |
49
+ | Session token | Local KXM tools | `session.token` (`0600`) in the user configuration directory, or `KXM_SESSION_TOKEN` | Local tool-policy checks and Studio mutation requests; never sent to the hub |
50
+ | Attempt capability | The Runtime, for one attempt | Only its SHA-256 hash is stored | Settling that one attempt; revoked on cancel |
51
+
52
+ `kxm hub start` generates an admin token (`kxm_admin_…`) when none exists and saves it, so a hub started that way always requires authentication. Give agents only their project token. Never give the admin token to an agent, a callback sender, or a dashboard that a project token can serve.
53
+
54
+ ### How clients choose a token
55
+
56
+ - **Claude Code plugin.** The MCP server uses the plugin's `auth_token` setting, else the project token the hub saved for this project. It never falls back to the saved admin token; without a project token, its tools report that and do nothing.
57
+ - **SessionStart hook.** It reads local state read-only. It mints no token, writes no file, and never prints a token.
58
+ - **Pi extension.** It uses `KXM_AUTH_TOKEN`, else the token from a hub it auto-started, else the saved admin token. When your project has its own project token, set `KXM_AUTH_TOKEN` to it for Pi, because the hub rejects the admin token for that project.
59
+ - **CLI and Runtime supervisor.** Operator tools use `KXM_AUTH_TOKEN`, else the saved project token, else the saved admin token.
60
+
61
+ ## Project isolation
62
+
63
+ A project is the unit of isolation on a hub:
64
+
65
+ - Every agent route checks the caller's project token and agent key together.
66
+ - A message can target only an agent in the sender's project.
67
+ - A context request outside the agent's project fails with `context_isolation_violation`.
68
+ - A webhook run belongs to the project named in its definition, not to the caller.
69
+ - The Runtime keeps a separate event store for every project.
70
+
71
+ A project listed in `KXM_PROJECT_TOKENS` accepts only its own token on agent routes. A project missing from the map falls back to the admin token, so the admin token can register agents under any unlisted project name. List every project you run so the admin token stops working on agent routes.
72
+
73
+ Isolation is logical. All projects on one hub share one process, one SQLite file, one log, and one in-memory rate limiter. Run a separate hub for teams that must not trust each other.
74
+
75
+ ## What provenance proves
76
+
77
+ In a hub workflow, a coordinator can ask peers for evidence. The hub stamps each request with the run, stage, requirement, and attempt. At a checkpoint it re-reads its own records, verifies every cited message, and counts unique producer identities toward the quorum. The coordinator never counts as a producer.
78
+
79
+ A verified quorum proves that the hub observed durable replies from the configured producer identities for this exact run, stage, requirement, and attempt. It does not prove:
80
+
81
+ - that any reply is correct or true;
82
+ - which model produced it, or that producers reasoned independently;
83
+ - that producers did not collude;
84
+ - that a person approved the result.
85
+
86
+ Every holder of one project token is inside the same provenance domain, because a project-token holder can register a new agent or reclaim an offline agent's name and durable ID. Issue a separate project token per trust domain. Degrading a quorum needs the admin token, must be allowed by the stage's policy, applies to one attempt, and is journaled. See [Provenance gates](../guides/provenance-gates.md).
87
+
88
+ ## Context authority
89
+
90
+ Context carries an authority level, and each origin can grant at most a fixed ceiling. The hub enforces the ceiling when it parses an item, and deriving new content from an item never raises its authority.
91
+
92
+ | Origin | Highest authority it can grant |
93
+ |---|---|
94
+ | `human`, `workflow` | `policy` |
95
+ | `git` | `instruction` |
96
+ | `peer`, `tool`, `external`, `derived` | `evidence` |
97
+
98
+ - A state proposal made with an agent key is **peer** origin, so it is capped at `evidence`.
99
+ - A **human**-origin proposal needs a configured admin token, with no loopback exception.
100
+ - `proposedBy` must name the authenticated caller, or the hub refuses the proposal.
101
+ - Promoting a proposal to current state needs a configured admin token and a promoter other than the author.
102
+ - Context items cannot carry control-plane fields such as `permissions`, `tools`, or `token`.
103
+ - A Runtime-dispatched agent receives memory and promoted skills only when they are committed, clean, and match the run's pinned memory revision.
104
+
105
+ See [Context and memory](../guides/context-and-memory.md).
106
+
107
+ ## Tool policy is a guardrail
108
+
109
+ Every call to one of the 19 KXM agent tools checks a tool policy first, whether it comes from Claude Code, Pi, or a matching CLI command such as `kxm peer send`. The check reads `KXM_ATTEMPT_TOKEN`, then `KXM_SESSION_TOKEN`, then the session token on disk. `kxm session brief` and `kxm auth token --issue` write that disk token with an operator preset and a 24-hour lifetime.
110
+
111
+ These tokens are unsigned JSON, so any local process can write one. Tool policy keeps a well-behaved agent inside its role; it does not stop a hostile one. An expired or malformed disk token denies every KXM agent tool until you remove it with `kxm session token --clear`. `kxm session token --status` reports no active token even while that expired file still blocks the tools.
112
+
113
+ ## Redaction and what stays local
114
+
115
+ - The hub's structured log omits prompt and reply bodies and redacts values by key name and by known credential patterns.
116
+ - The operations stream and `kxm dash` carry metadata only, never bodies.
117
+ - The Runtime-to-hub sync builds a new event from an allowlist. Raw prompts, raw logs, diffs, environment values, and absolute paths never leave the machine that way. Registered secrets and credential shapes are replaced, and unknown fields are dropped.
118
+ - Provider credentials never reach the hub, because the hub never runs an agent.
119
+
120
+ Redaction is pattern-based and best effort. Message bodies, workflow evidence, the journal, and Runtime prompts and event payloads are stored as sent. [Data and storage](data-and-storage.md) lists what each store keeps.
121
+
122
+ ## Network exposure
123
+
124
+ - The hub binds `127.0.0.1` by default and refuses to bind beyond loopback without an admin token. Started directly on loopback without a token, it prints `auth=none` and trusts every local caller.
125
+ - The Runtime supervisor binds `127.0.0.1` only. Its health check answers a nonce with a keyed proof, so a client can tell the real supervisor from a process that took over a stale port.
126
+ - `kxm studio serve` binds `127.0.0.1` by default and allows any browser origin. Keep it on loopback.
127
+ - The hub's rate limit is per agent ID or remote address and lives in memory. It is a courtesy limit, not abuse protection.
128
+ - Webhook signatures are HMAC-SHA256 over the raw body with no timestamp window. A replayed delivery is deduplicated by its delivery ID, not rejected, until its run is purged after 7 days.
129
+ - Binding a machine to a remote hub (`kxm hub bind`) requires a credential for that hub.
130
+
131
+ For a hosted hub, KXM uses one tenant per box. Browsers authenticate at an HTTPS proxy with Authentik, a portal backend calls the loopback hub and Runtime with machine credentials, and no hub port is public. The hub never reads browser identity headers. See [Deploy KXM](../operations/deploy.md) and [ADR-0004](../adr/ADR-0004-edge-identity-authentik.md).
132
+
133
+ ## KXM is not a sandbox
134
+
135
+ > [!WARNING]
136
+ > KXM does not isolate processes that run as the same OS user. A shell-capable agent can read any file that account can read, including hub state, tokens, and Pi session files.
137
+
138
+ - `KXM_WORKER_TOOLS` limits which tools a Pi worker may call, not which paths it may touch.
139
+ - Role descriptions and prompt instructions document intent; they do not remove shell, edit, or write tools.
140
+ - Workflow session isolation keeps model contexts apart; it is not a security boundary.
141
+ - Peer output stays untrusted even when the peer is authenticated.
142
+
143
+ When an agent is outside your trust boundary, run it under a separate OS account or container, give it a read-only worktree, and withhold shell and write tools.
144
+
145
+ ## Related
146
+
147
+ - [Architecture](architecture.md)
148
+ - [Data and storage](data-and-storage.md)
149
+ - [Security policy](../../SECURITY.md)
150
+ - [Provenance gates](../guides/provenance-gates.md)
151
+ - [Deploy KXM](../operations/deploy.md)
152
+ - [ADR-0004: Edge identity with Authentik](../adr/ADR-0004-edge-identity-authentik.md)