@kontextmind/kxm 0.7.95 → 0.7.97

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.kxm/README.md +39 -9
  3. package/CHANGELOG.md +23 -1
  4. package/README.md +147 -257
  5. package/SECURITY.md +21 -12
  6. package/docs/README.md +133 -54
  7. package/docs/adr/ADR-0002-browser-automation-steel-doks.md +24 -18
  8. package/docs/adr/ADR-0003-sqlite-only-store.md +100 -0
  9. package/docs/adr/ADR-0004-edge-identity-authentik.md +99 -0
  10. package/docs/adr/README.md +33 -0
  11. package/docs/concepts/architecture.md +262 -0
  12. package/docs/concepts/data-and-storage.md +194 -0
  13. package/docs/concepts/trust-model.md +153 -0
  14. package/docs/contracts/README.md +22 -14
  15. package/docs/contracts/effects-and-recovery.md +3 -0
  16. package/docs/contracts/migration.md +2 -2
  17. package/docs/contracts/routing.md +6 -5
  18. package/docs/contributing/assignment-runner.md +388 -0
  19. package/docs/contributing/ci-and-release.md +231 -0
  20. package/docs/contributing/development.md +362 -0
  21. package/docs/contributing/harness-routing-internals.md +192 -0
  22. package/docs/{packages.md → contributing/packages.md} +13 -15
  23. package/docs/{skills → contributing}/repo-work-delivery.md +20 -21
  24. package/docs/contributing/test-matrix.md +208 -0
  25. package/docs/{tui-components.md → contributing/tui-components.md} +30 -22
  26. package/docs/contributing/writing-docs.md +340 -0
  27. package/docs/glossary.md +471 -0
  28. package/docs/guides/agent-skills.md +137 -0
  29. package/docs/guides/browser-automation.md +160 -0
  30. package/docs/guides/context-and-memory.md +352 -0
  31. package/docs/guides/continuous-improvement.md +228 -0
  32. package/docs/guides/governed-skills.md +173 -0
  33. package/docs/guides/nous-providers.md +186 -0
  34. package/docs/guides/peer-messaging.md +304 -0
  35. package/docs/guides/pi-workers.md +219 -0
  36. package/docs/guides/provenance-gates.md +313 -0
  37. package/docs/guides/webhook-workflows.md +399 -0
  38. package/docs/kb/how-credentials-retrieved-safely.md +38 -12
  39. package/docs/kb/how-to-capture-and-annotate-section.md +15 -13
  40. package/docs/kb/how-to-connect-playwright-to-steel.md +16 -11
  41. package/docs/kb/how-to-recover-expired-session-or-orphan.md +26 -16
  42. package/docs/kb/how-to-resume-after-mfa.md +19 -11
  43. package/docs/kb/how-to-take-over-session.md +17 -13
  44. package/docs/kb/why-authentication-disappeared.md +22 -14
  45. package/docs/kb/why-automation-opened-different-browser.md +23 -14
  46. package/docs/kb/why-session-viewer-cannot-control.md +13 -12
  47. package/docs/operations/backup-and-restore.md +248 -0
  48. package/docs/operations/deploy.md +307 -0
  49. package/docs/operations/monitoring.md +209 -0
  50. package/docs/operations/runtime-sync.md +192 -0
  51. package/docs/operations/troubleshooting.md +266 -0
  52. package/docs/operations/upgrade.md +124 -0
  53. package/docs/prompts/browser-annotate-feedback.md +7 -7
  54. package/docs/prompts/browser-diagnose-recover.md +11 -10
  55. package/docs/prompts/browser-explore.md +7 -7
  56. package/docs/prompts/browser-repro-fix.md +7 -7
  57. package/docs/prompts/browser-start.md +12 -11
  58. package/docs/prompts/browser-takeover.md +8 -8
  59. package/docs/{cli-reference.md → reference/cli-reference.md} +88 -46
  60. package/docs/{config-reference.md → reference/config-reference.md} +159 -148
  61. package/docs/reference/configuration.md +299 -0
  62. package/docs/reference/harness-routing.md +508 -0
  63. package/docs/reference/http-api.md +203 -0
  64. package/docs/reference/tools.md +370 -0
  65. package/docs/{workflow-guide.md → reference/workflow-catalog.md} +92 -153
  66. package/docs/reference/workflow-definitions.md +286 -0
  67. package/docs/start/first-workflow.md +287 -0
  68. package/docs/start/install.md +146 -0
  69. package/docs/start/quickstart-claude-code.md +405 -0
  70. package/docs/start/quickstart-pi.md +213 -0
  71. package/docs/templates/README.md +78 -73
  72. package/docs/templates/adr.md +13 -13
  73. package/docs/templates/architecture.md +55 -71
  74. package/docs/templates/bug-fix.md +13 -16
  75. package/docs/templates/feature.md +14 -19
  76. package/docs/templates/handoff.md +44 -46
  77. package/docs/templates/postmortem.md +30 -43
  78. package/docs/templates/research.md +15 -20
  79. package/docs/templates/review.md +49 -50
  80. package/docs/templates/runbook.md +38 -30
  81. package/docs/templates/test-plan.md +16 -23
  82. package/docs/templates/test-report.md +14 -17
  83. package/examples/README.md +9 -5
  84. package/examples/provenance-workflow.json +1 -1
  85. package/examples/webhook-workflows/jira-development.json +59 -0
  86. package/examples/webhook-workflows/jira-issue-updated.json +12 -0
  87. package/examples/workflow-signal.ts +4 -5
  88. package/package.json +1 -1
  89. package/packages/core/tui/README.md +1 -1
  90. package/plugins/kxm/.claude-plugin/plugin.json +1 -1
  91. package/plugins/kxm/README.md +31 -32
  92. package/plugins/kxm/dist/claude-hook.js +11 -1
  93. package/plugins/kxm/dist/cli.js +164 -79
  94. package/plugins/kxm/dist/client.js +3 -1
  95. package/plugins/kxm/dist/core.js +11 -1
  96. package/plugins/kxm/dist/extension.js +45 -13
  97. package/plugins/kxm/dist/mcp-server.js +20 -4
  98. package/plugins/kxm/dist/runtime-supervisor.js +1 -3
  99. package/plugins/kxm/dist/runtime.js +18 -4
  100. package/plugins/kxm/dist/server.js +115 -20
  101. package/plugins/kxm/package.json +1 -1
  102. package/plugins/kxm/skills/kxm/references/protocol.md +3 -1
  103. package/plugins/kxm/skills/kxm-browser-auth/SKILL.md +1 -1
  104. package/plugins/kxm/skills/kxm-browser-diagnostics/SKILL.md +5 -5
  105. package/plugins/kxm/skills/kxm-browser-explore/SKILL.md +2 -2
  106. package/plugins/kxm/skills/kxm-browser-session/SKILL.md +10 -13
  107. package/plugins/kxm/skills/kxm-browser-takeover/SKILL.md +1 -1
  108. package/plugins/kxm/skills/kxm-browser-verify/SKILL.md +1 -1
  109. package/plugins/kxm/skills/kxm-context-memory/SKILL.md +13 -4
  110. package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +3 -1
  111. package/plugins/kxm/skills/kxm-mind-setup/SKILL.md +2 -1
  112. package/plugins/kxm/skills/kxm-project-setup/SKILL.md +31 -54
  113. package/plugins/kxm/skills/kxm-projects/SKILL.md +1 -1
  114. package/plugins/kxm/skills/kxm-protocol/SKILL.md +1 -1
  115. package/plugins/kxm/skills/kxm-routing-improve/SKILL.md +15 -7
  116. package/plugins/kxm/skills/kxm-runs/SKILL.md +11 -5
  117. package/plugins/kxm/skills/kxm-session/SKILL.md +1 -1
  118. package/plugins/kxm/skills/kxm-tasks/SKILL.md +9 -7
  119. package/plugins/kxm/skills/kxm-workflow/SKILL.md +10 -2
  120. package/plugins/kxm/src/cli/system.ts +1 -1
  121. package/plugins/kxm/src/cli/workflows.ts +12 -7
  122. package/plugins/kxm/src/cli.ts +22 -8
  123. package/plugins/kxm/src/client.ts +4 -0
  124. package/plugins/kxm/src/commands.ts +23 -1
  125. package/plugins/kxm/src/extension.ts +20 -14
  126. package/plugins/kxm/src/github-watch.ts +8 -5
  127. package/plugins/kxm/src/hub-env.ts +19 -1
  128. package/plugins/kxm/src/hub.ts +105 -21
  129. package/plugins/kxm/src/improve-sources.ts +2 -7
  130. package/plugins/kxm/src/init-guide-setup.ts +1 -1
  131. package/plugins/kxm/src/mcp-server.ts +9 -2
  132. package/plugins/kxm/src/modes.ts +1 -1
  133. package/plugins/kxm/src/runtime-store.ts +23 -0
  134. package/plugins/kxm/src/workflow.ts +70 -1
  135. package/schemas/README.md +1 -1
  136. package/scripts/smoke-multi-pi.mjs +5 -1
  137. package/docs/agent-communication-envelopes-and-gates.md +0 -553
  138. package/docs/agent-skills.md +0 -198
  139. package/docs/architecture.md +0 -245
  140. package/docs/assignment-runner.md +0 -264
  141. package/docs/browser-automation.md +0 -139
  142. package/docs/configuration.md +0 -437
  143. package/docs/continuous-improvement.md +0 -226
  144. package/docs/getting-started.md +0 -277
  145. package/docs/harness-routing.md +0 -616
  146. package/docs/kb/qa-authentik-authentication.md +0 -97
  147. package/docs/kb/qa-extension-install-and-hub-bootstrap.md +0 -85
  148. package/docs/kb/qa-hub-on-a-public-host.md +0 -48
  149. package/docs/kb/qa-sqlite-vs-duckdb.md +0 -35
  150. package/docs/kb/qa-what-the-hub-stores.md +0 -64
  151. package/docs/kxm-handbook.md +0 -1181
  152. package/docs/operations.md +0 -510
  153. package/docs/operator-pi-packages.md +0 -67
  154. package/docs/provenance-gates.md +0 -295
  155. package/docs/skills.md +0 -47
  156. package/docs/test-matrix.md +0 -132
  157. package/docs/troubleshooting.md +0 -322
  158. package/docs/webhook-workflows.md +0 -240
@@ -3,18 +3,20 @@
3
3
  This page describes every file a KXM project or operator configures: where it
4
4
  lives, which parser reads it, every field that parser accepts, the error codes
5
5
  it reports, and which commands read or write it. It was written against the
6
- parsers in `plugins/kxm/src` and `scripts/` for KXM 0.7.1, and every example on
6
+ parsers in `plugins/kxm/src` and `scripts/`, and every example on
7
7
  this page was validated with the commands named next to it. Where a field is
8
8
  accepted but nothing acts on it yet, the tables say so.
9
9
 
10
10
  Related pages:
11
11
 
12
- - [Configuration](configuration.md) lists the environment variables for the hub,
13
- workers, and agents.
12
+ - [Environment variables and limits](configuration.md) lists the environment
13
+ variables for the hub, workers, and agents, and the protocol limits.
14
+ - [Workflow definitions](workflow-definitions.md) documents the hub's JSON
15
+ webhook workflow definitions field by field.
14
16
  - [Harness routing](harness-routing.md) explains when to run a model through its
15
17
  native harness and when to reach the same model through OpenRouter on Pi. This
16
18
  page documents the fields; that guide covers the decision.
17
- - [Operations](operations.md) covers backup and restore of every path below.
19
+ - [Backup and restore](../operations/backup-and-restore.md) covers every path below.
18
20
 
19
21
  ## At a glance
20
22
 
@@ -141,7 +143,7 @@ makes a directory a KXM project. Parser: `loadKxmProject` in
141
143
  | Field | Type and allowed values | Required, default | What reads it |
142
144
  |---|---|---|---|
143
145
  | `schema` | `kxm.project.v1` | Required | Loader |
144
- | `id` | Opaque ID matching `^[a-z][a-z0-9]{1,15}_[A-Za-z0-9][A-Za-z0-9_-]{5,127}$` | Required | Loader, Runtime. `kxm init` generates `prj_` plus 32 hex characters; `--project-id` must start with `prj_`. The Runtime binds one ID to one control root per state root, so a second checkout with the same ID is refused with `project_home_conflict`. |
146
+ | `id` | Opaque ID matching `^[a-z][a-z0-9]{1,15}_[A-Za-z0-9][A-Za-z0-9_-]{5,127}$` | Required | Loader, Runtime. `kxm init` generates `prj_` plus 32 hex characters; `--project-id` must start with `prj_`. See the note below |
145
147
  | `name` | String, 1 to 120 characters | Required | Display only |
146
148
  | `description` | String, at most 2,000 characters | Optional | Display only |
147
149
  | `defaultWorkflow` | Identifier | Optional, `default` | Loader only: the named workflow must exist (`default_workflow_unknown`). `kxm run` always takes an explicit workflow. |
@@ -164,6 +166,9 @@ makes a directory a KXM project. Parser: `loadKxmProject` in
164
166
  | `limits.maxRunDurationMs` | Integer, 0 to 31,536,000,000 | Optional | Runtime. Combined with the workflow's own value; the smaller one wins. |
165
167
  | `limits.maxAgentTimeMs` | Integer, 0 to 31,536,000,000 | Optional | Runtime refuses to drive any run while it is set (`limit_unsupported`); leave it out |
166
168
 
169
+ The Runtime binds one project `id` to one control root per state root, so a
170
+ second checkout with the same ID is refused with `project_home_conflict`.
171
+
167
172
  Example (validated with `kxm init --json`, including a nested member checkout
168
173
  at `repositories/api`):
169
174
 
@@ -374,7 +379,7 @@ checks it when it probes the harness before dispatch.
374
379
  | `agy` | Provider `google` and `gemini-` models |
375
380
  | `kimi` | Provider `moonshot` and `kimi`, `moonshot`, or `kimi-for-coding` models |
376
381
  | `deepseek` | Provider `deepseek` and `deepseek-` models |
377
- | `pi` | Any provider except `anthropic`, `openai`, `xai`, `moonshot`, `google`, and `deepseek` (`pi_native_impersonation_blocked`); use the native harness for those |
382
+ | `pi` | Refuses a native vendor's model named directly, through the vendor's Pi provider or behind an aggregator, except `antigravity/gemini-…` (`pi_native_impersonation_blocked`); see [the brake](harness-routing.md#what-the-brake-refuses) |
378
383
 
379
384
  A mismatch is reported as `harness_unhosted_model`. Which route to choose for a
380
385
  model that more than one harness can reach is covered in
@@ -500,7 +505,9 @@ ID used by `kxm run <workflow>`. Three layers check it:
500
505
  1. The loader (`schemas/workflow.schema.json` plus `validateWorkflow` in
501
506
  `plugins/kxm/src/project-config.ts`) on every project load.
502
507
  2. The compiler (`compileKxmWorkflow` in `plugins/kxm/src/engine-compile.ts`)
503
- when `kxm run` creates a run. It pins the compiled plan on the run.
508
+ when the first `kxm runs drive` starts the run. It pins the compiled plan
509
+ on the run then, not when `kxm run` creates it, and it refuses the run
510
+ (`run_revision_drift`) if the configuration changed in between.
504
511
  3. Runtime acceptance (`plugins/kxm/src/engine.ts`) before each step executes.
505
512
  A step the current Runtime cannot execute hands the run off instead of
506
513
  running it.
@@ -511,17 +518,21 @@ ID used by `kxm run <workflow>`. Three layers check it:
511
518
  |---|---|---|---|
512
519
  | `schema` | `kxm.workflow.v1` | Required | |
513
520
  | `description` | String, at most 4,000 characters | Optional | Prose; neutral in `kxm trust` |
514
- | `coordinator` | Agent ID | Optional, `coordinator` | Must exist (`coordinator_unknown`); pinned on the compiled plan. Approval and wait steps without `assignments.allowedAgents` are dispatched to the agent whose ID is literally `coordinator`, not to this field's value. |
521
+ | `coordinator` | Agent ID | Optional, `coordinator` | Must exist (`coordinator_unknown`); pinned on the compiled plan. See the note on approval and wait steps below. |
515
522
  | `limits.maxTransitions` | Integer, 1 to 1,000 | Required once any back-edge exists (`workflow_cycle_unbounded`) | Run-wide transition budget; defaults to the number of steps. Exceeding it fails the run with `budget_transitions`. |
516
- | `limits.maxRunDurationMs` | Integer, 0 to 31,536,000,000 | Optional | The Runtime cancels the run with `budget_run_duration`; the smaller of this and the project limit applies |
517
- | `limits.maxAgentTimeMs` | Integer, 0 to 31,536,000,000 | Optional | The Runtime refuses to drive a run that declares it (`limit_unsupported`; the CLI reports `run_handoff_required`). The built-in template sets it, so the template's `default` workflow cannot be driven as generated. |
523
+ | `limits.maxRunDurationMs` | Integer, 0 to 31,536,000,000 | Optional | The Runtime cancels the run with `budget_run_duration`; the smaller of this and the project limit applies. Measured on the wall clock |
524
+ | `limits.maxAgentTimeMs` | Integer, 0 to 31,536,000,000 | Optional | The Runtime refuses to drive a run that declares it (`limit_unsupported`); see below |
518
525
  | `limits.maxModelCost` | Number greater than 0 | Optional | Fails the run with `budget_model_cost` once attempts recorded with cost basis `metered` reach it. See [Cost basis](#cost-basis-and-staleness). |
519
526
  | `limits.currency` | Three uppercase letters | Optional | Pinned on the plan; not otherwise read |
520
- | `planHash` | `{stageId, evidenceKey}` | Optional | When `stageId` passes, the hash of that evidence is captured. The step must declare that evidence key (`oracle_evidence_unknown`, `oracle_stage_unknown`). |
521
- | `reproOracle` | `{stageId, evidenceKey}` | Optional | Same shape as `planHash`, for an immutable reproduction |
522
- | `requirePlanHash` | Unique step IDs, at most 128 | Optional | Requires `planHash` (`plan_hash_missing`); every step that writes a repository after the `planHash` stage must be listed (`mutation_missing_plan_hash`) |
527
+ | `planHash` | `{stageId, evidenceKey}` | Optional | Validated and pinned, not enforced yet (see below). The step must declare that evidence key (`oracle_evidence_unknown`, `oracle_stage_unknown`). |
528
+ | `reproOracle` | `{stageId, evidenceKey}` | Optional | Same shape as `planHash`, for an immutable reproduction; validated and pinned, not enforced yet |
529
+ | `requirePlanHash` | Unique step IDs, at most 128 | Optional | Requires `planHash` (`plan_hash_missing`); every repository-writing step after the `planHash` stage must be listed (`mutation_missing_plan_hash`) |
523
530
  | `steps` | 1 to 128 steps | Required | The first step is the entry point |
524
531
 
532
+ Approval and wait steps without `assignments.allowedAgents` are dispatched to the agent whose ID is literally `coordinator`, not to the `coordinator` field's value.
533
+
534
+ Duration budgets use the wall clock. `maxRunDurationMs` counts from the time the run first entered `running` (its first drive) to the current system time, so a change to the system clock moves it.
535
+
525
536
  ### Step fields
526
537
 
527
538
  | Field | Type and allowed values | Required, default | Notes |
@@ -536,7 +547,7 @@ ID used by `kxm run <workflow>`. Three layers check it:
536
547
  | `signal` | Identifier | Required for `wait` | Compiled and diffed; the Runtime does not match signals to wait steps yet |
537
548
  | `model` | Model selector | Optional | Intersected with each allowed agent's own model ceiling; an empty intersection is `model_selector_incompatible`. Live route resolution ignores it. The Runtime refuses it on gate steps. |
538
549
  | `maxAttempts` | Integer, 1 to 20 | Optional, `1` | Entering the step again after this many attempts fails the run (`budget_step_attempts`) |
539
- | `timeoutMs` | Integer, 0 to 31,536,000,000 | Optional | Gate steps: refused on `artifacts-exist` gates and when shorter than the command gate's own `timeoutMs`. Other kinds: pinned but not passed to the producer yet (the live one-shot producer uses its own 120-second process timeout). `0` is refused. |
550
+ | `timeoutMs` | Integer, 0 to 31,536,000,000 | Optional | Not `0`. Gate steps: refused for `artifacts-exist` gates or below the gate's `timeoutMs`. Other kinds: unused; the producer times out at 120 s |
540
551
  | `repositories` | Map of repository ID to `none`, `read`, or `write` | Optional | IDs must be declared (`repository_unknown`); may not exceed the agent's ceiling (`repository_scope_expansion`) |
541
552
  | `tools` | `{preset, allow, deny}` | Optional | Must keep the agent's preset and denials and allow only tools the agent allows (`tool_scope_expansion`). The Runtime refuses steps that declare `tools`. |
542
553
  | `secrets` | `[{ref, as, required}]` | Optional | Only refs the agent grants (`secret_scope_expansion`). The Runtime refuses steps that declare `secrets`. |
@@ -548,7 +559,7 @@ ID used by `kxm run <workflow>`. Three layers check it:
548
559
 
549
560
  Fields such as `role`, `area`, or `outcomes` are not part of this schema and
550
561
  fail with `schema_additionalProperties`. `area` belongs to
551
- [webhook workflow stages](#webhook-workflow-definitions); the compiled plan
562
+ [webhook workflow stages](workflow-definitions.md#stage-fields); the compiled plan
552
563
  derives its outcome list from the keys of `on`.
553
564
 
554
565
  ### Assignments and join
@@ -560,13 +571,24 @@ derives its outcome list from the keys of `on`.
560
571
  | `assignments.target` | Integer, 1 to 64 | `minimum` | |
561
572
  | `assignments.maximum` | Integer, 1 to 64 | `target` | For `moa`, at most the number of allowed agents (`assignment_pool_too_small`) |
562
573
  | `assignments.maxParallel` | Integer, 1 to 64 | `maximum` | At most `maximum` (`assignment_parallelism_invalid`) |
563
- | `assignments.maxAttemptsPerAssignment` | Integer, 1 to 20 | `1` | The Runtime executes at most 2 |
574
+ | `assignments.maxAttemptsPerAssignment` | Integer, 1 to 20 | `1` | The Runtime accepts at most 2, but runs one attempt per assignment; a retry is a new assignment |
564
575
  | `assignments.maxWriteRepositories` | Integer, 1 to 64 | none | At most the number of `write` repositories on the step (`write_repository_bound_invalid`); the Runtime executes at most 1 |
565
- | `assignments.distinctBy` | Any of `provider`, `model`, `profile` | `[]` | The resolved candidates must offer `target` distinct values (`model_diversity_impossible`); the Runtime executes only `provider` |
566
- | `join.strategy` | `all`, `all-settled`, `quorum`, or `first-success` | `all` | The Runtime executes `all` and `all-settled` |
576
+ | `assignments.distinctBy` | Any of `provider`, `model`, `profile` | `[]` | Checked at load only: the candidates must offer `target` distinct values (`model_diversity_impossible`). The Runtime refuses values other than `provider` |
577
+ | `join.strategy` | `all`, `all-settled`, `quorum`, or `first-success` | `all` | The Runtime executes `all` and `all-settled` (see [How a panel joins](#how-a-panel-joins)) |
567
578
  | `join.minimumPassed` | Integer, 1 to 64 | none | Required for `quorum`; at most `maximum` (`join_impossible`); the Runtime accepts it only with `all-settled` |
568
579
  | `join.cancelRemaining` | Boolean | none | The Runtime refuses it |
569
580
 
581
+ At run time, members bind to agents in `allowedAgents` order: the first member runs the first listed agent, the second the second, and so on. The Runtime does not re-check providers, so `distinctBy: [provider]` holds at run time only if the first `target` agents in `allowedAgents` use different providers. List them that way.
582
+
583
+ #### How a panel joins
584
+
585
+ A panel joins once at least `assignments.minimum` members exist and every member's attempt has settled:
586
+
587
+ - If any member's result is unknown or rejected by its producer, the run fails with `outcome_unknown`.
588
+ - `all`: when every member produced the same outcome, the step takes it; otherwise the run fails with `join_conflict`.
589
+ - `all-settled`: when at least `join.minimumPassed` members (default `assignments.minimum`) passed, the outcome is `passed`. Otherwise, a non-passed outcome shared by that many members wins, and failing that the outcome is `quorum-not-met`.
590
+ - A joined outcome with no transition in `on` fails the run with `outcome_unknown`, so declare `quorum-not-met` on an `all-settled` step.
591
+
570
592
  ### Evidence requirements
571
593
 
572
594
  | Field | Type and allowed values | Default | Notes |
@@ -582,6 +604,8 @@ derives its outcome list from the keys of `on`.
582
604
 
583
605
  A `producerPolicy` is allowed only on `kind: assignment-result`.
584
606
 
607
+ The Runtime enforces less of this than the loader checks. `producerPolicy` (producer counts, eligible agents, degradation) is checked at load only. On agent and `moa` steps, each requirement only becomes an acceptance criterion in the prompt; nothing checks that the evidence arrived. Only gate steps record evidence at run time: one gate evidence reference for each settled gate attempt.
608
+
585
609
  ### Transitions and outcomes
586
610
 
587
611
  Each key of `on` is an outcome identifier. Each value is either a step ID
@@ -645,9 +669,12 @@ falls back to it.
645
669
 
646
670
  Validation accepts more than the Runtime executes. When a drive reaches one of
647
671
  these, the run is handed off (`step_unsupported`, `gate_unsupported`, or
648
- `limit_unsupported`) instead of executing:
672
+ `limit_unsupported`) instead of executing, and `kxm runs drive` reports
673
+ `run_handoff_required`:
649
674
 
650
- - `limits.maxAgentTimeMs` in the workflow or project.
675
+ - `limits.maxAgentTimeMs` in the workflow or project. The built-in template
676
+ sets it, so the `default` workflow that `kxm init` writes cannot be driven
677
+ as generated.
651
678
  - `tools`, `secrets`, or `safeSpeculation: true` on any step.
652
679
  - `join.strategy` other than `all` or `all-settled`, `join.minimumPassed` with
653
680
  `all`, and `join.cancelRemaining`.
@@ -663,9 +690,35 @@ these, the run is handed off (`step_unsupported`, `gate_unsupported`, or
663
690
  `write` access to `control` or with access to any other repository; a
664
691
  `reserved` gate.
665
692
 
693
+ Some fields are validated and pinned on the plan but not enforced, and a
694
+ drive does not hand off on them:
695
+
696
+ - `planHash`, `reproOracle`, and `requirePlanHash`. The Runtime captures no
697
+ hash and does not check one before a listed step runs. (Hub
698
+ [webhook workflows](workflow-definitions.md#plan-hash-and-reproduction-oracle)
699
+ do enforce their own `planHash` and `reproOracle`.)
700
+ - `distinctBy: [provider]` and `producerPolicy`, which are checked at load only
701
+ (see [Assignments and join](#assignments-and-join) and
702
+ [Evidence requirements](#evidence-requirements)).
703
+
666
704
  The Runtime also caps each run at 100 attempts whose cost basis is `unmetered`
667
705
  or `unknown` (`budget_unmetered_attempts`).
668
706
 
707
+ #### Handoff reasons
708
+
709
+ A handoff stops the drive without failing the run; `kxm runs drive` prints
710
+ the reason, field, and detail. The Runtime uses these reasons:
711
+
712
+ | Reason | Meaning |
713
+ |---|---|
714
+ | `step_unsupported`, `gate_unsupported`, `limit_unsupported` | The step, gate, or limit is one the Runtime does not execute yet (the list above) |
715
+ | `gate_outcome_undeclared` | The drive-time gate pre-flight check failed (see [Transitions and outcomes](#transitions-and-outcomes)) |
716
+ | `attempt_unsettled` | A gate attempt could not settle: its effect is uncertain, or its outcome has no transition |
717
+ | `gate_recovery_pending` | Unfinished gate attempts elsewhere in the project hold later gate steps |
718
+ | `attempt_unreconciled` | An issued attempt is not held by this process, for example after a supervisor restart |
719
+ | `cancel_pending_foreign` | Cancellation is pending in another process |
720
+ | `gate_uncertain_blocked` | The run is `blocked_uncertain` and waits for an external signal or an operator |
721
+
669
722
  Example (validated with `kxm init --json` and compiled with
670
723
  `compileKxmWorkflow`). Besides the `implementer` and `critic-arch` agents and
671
724
  the `critic-claude` profile shown above, it needs a `coordinator` agent, a
@@ -814,9 +867,10 @@ This example validates, but a live drive would be handed off at `implement`
814
867
  it as a field reference; the
815
868
  [worked example](#worked-example-a-minimal-two-step-project) is one that runs.
816
869
 
817
- Commands: `kxm init` validates; `kxm run <id> [prompt]` compiles and creates a
818
- run (`--dry-run` only loads the bundle); `kxm runs drive <runId> --simulated`
819
- drives without models; `kxm runs status|list|cancel`; `kxm trust` diffs.
870
+ Commands: `kxm init` validates; `kxm run <id> [prompt]` creates a run
871
+ (`--dry-run` only loads the bundle); the first `kxm runs drive <runId>`
872
+ compiles and pins the plan, then drives it live, or without models with
873
+ `--simulated`; `kxm runs status|list|cancel`; `kxm trust` diffs.
820
874
  `kxm workflow add <id> --template <name>` writes a built-in template
821
875
  (`implement-and-verify`, `dual-critic-review`, or `spec-and-plan`), and
822
876
  `kxm workflow add <id>` a one-step scaffold, under `.kxm/workflows/` (or
@@ -850,6 +904,15 @@ code decides the outcome (see
850
904
  [Transitions and outcomes](#transitions-and-outcomes)); the Runtime records
851
905
  hashes and byte counts of stdout and stderr, not their text.
852
906
 
907
+ Before it starts the process, the Runtime checks the joined `argv` against the
908
+ destructive-command seatbelt (`rm` with recursive and force flags,
909
+ `git reset --hard`, `git clean -f`, `git checkout --` with paths, and
910
+ `git restore .` or `*`); a match starts nothing and fails the run with
911
+ `gate_start_failed`. The command runs in its own
912
+ process group. On timeout or cancellation the Runtime sends `SIGTERM` to the
913
+ group, then `SIGKILL` after 2 seconds. A process that escapes the group can
914
+ outlive the gate, so the seatbelt and the group are cleanup, not a sandbox.
915
+
853
916
  ```yaml
854
917
  # .kxm/gates.yaml — the only place a gate id becomes executable.
855
918
  schema: kxm.gate-registry.v1
@@ -885,10 +948,15 @@ read different fields:
885
948
 
886
949
  | Reader | File | Fields it reads | Effect |
887
950
  |---|---|---|---|
888
- | Project loader (`validateBundle`) | `.kxm/roles/writer.yaml` only | `roster[].model`, `roster[].enabled` | If the agent `implementer` (or else `writer`) declares a model and the roster has at least one enabled entry, one enabled entry must equal `provider/model`, equal the bare model, or end with `/<model>`; otherwise `role_roster_conflicts_with_agent`. Parsed as restricted YAML. |
951
+ | Project loader (`validateBundle`) | `.kxm/roles/writer.yaml` only | `roster[].model`, `roster[].enabled` | Cross-checks the writer roster against the `implementer` agent's model (see below). Parsed as restricted YAML. |
889
952
  | Runtime route check (`listRoleBindings` in `plugins/kxm/src/routes.ts`) | `.kxm/roles/<role>.yaml`, role = agent ID, `writer` for `implementer` | `roster[].model` | The agent's `provider/model` must appear exactly. `enabled` is ignored, so a disabled entry still admits. The role name comes from the filename. |
890
953
  | `kxm role` commands (`plugins/kxm/src/role.ts`) | `.kxm/roles/*.yaml` and `~/.config/kxm/roles/*.yaml` | Everything below | Listing and editing only. A file without `schema: kxm.role.v1` is silently skipped. A local file overrides a global one with the same ID. |
891
954
 
955
+ The loader check applies when the agent `implementer` (or else `writer`)
956
+ declares a model and the roster has at least one enabled entry. One enabled
957
+ entry must then equal `provider/model`, equal the bare model, or end with
958
+ `/<model>`; otherwise the load fails with `role_roster_conflicts_with_agent`.
959
+
892
960
  Write roster models as the full `provider/model` string. `kxm role add --model
893
961
  grok-4.6` writes a bare model ID, which satisfies the loader check but not the
894
962
  Runtime route check. `kxm role modify <role> --add-model grok:xai/grok-4.6`
@@ -977,7 +1045,7 @@ unknown keys are ignored).
977
1045
  | `schema` | `kxm.routes.v2` | Required | Anything else fails with `invalid .kxm/routes.yaml` |
978
1046
  | `admitted` | Array of route strings | Required | Runtime route check; `kxm routes list`, `kxm routes count`; `kxm models` |
979
1047
  | `disabled` | Array of route strings | Optional, `[]` | Runtime: a disabled route is refused even if admitted |
980
- | `roles` | Map of name to route strings | Optional, `{}` | Not read by any code path yet; shown by `kxm routes list` and preserved on rewrite. Role rosters live in `.kxm/roles/`. |
1048
+ | `roles` | Map of name to route strings | Optional, `{}` | Not read by any code path yet; shown only by `kxm routes list --json`, and preserved on rewrite. Role rosters live in `.kxm/roles/` |
981
1049
  | `updatedAt` | ISO timestamp string | Optional | Rewritten by every CLI change |
982
1050
 
983
1051
  A route string is exactly the agent's `model.provider`, a slash, and
@@ -1020,7 +1088,7 @@ report them; review them in the pull request diff.
1020
1088
  ## `.kxm/roster.yaml` (`kxm.developer-roster.v1`)
1021
1089
 
1022
1090
  The developer roster for `scripts/assignment-run.mjs` (the `just` assignment
1023
- recipes; see [Assignment runner](assignment-runner.md)). It applies to the KXM
1091
+ recipes; see [Assignment runner](../contributing/assignment-runner.md)). It applies to the KXM
1024
1092
  source repository itself: the loader in `scripts/roster-policy.mjs` reads the
1025
1093
  copy committed at `HEAD` of the repository that contains the script, and
1026
1094
  refuses unless the worktree is clean, `HEAD` is an ancestor of
@@ -1212,11 +1280,14 @@ models:
1212
1280
  cacheReadPerMillion: 0.25
1213
1281
  ```
1214
1282
 
1215
- Commands: the Pi and one-shot producers read it on every attempt;
1216
- `kxm explain` reports `catalogStatus` (`verified`, `stale`, `corrupt`, or
1217
- `missing`); `kxm routing report --list-prices [--prices <file>]` reads it
1218
- (default `<workspace>/prices.yaml`, normally `.kxm/prices.yaml`) and ignores a
1219
- bad file.
1283
+ Commands: the one-shot producer, which the Runtime uses for every harness,
1284
+ reads it on every attempt and ignores a catalog not dated today (the package's
1285
+ long-lived Pi producer also reads it, but nothing in the Runtime calls that
1286
+ producer today); `kxm explain` reports `catalogStatus` (`verified`, `stale`,
1287
+ `corrupt`, or `missing`); `kxm routing report --list-prices [--prices <file>]`
1288
+ reads it (default `<workspace>/prices.yaml`, normally `.kxm/prices.yaml`) and
1289
+ ignores a bad file. The report skips the freshness check, so it prices with a
1290
+ catalog of any date, including one the producers treat as stale.
1220
1291
 
1221
1292
  ## `.kxm/models/inventory.yaml` (`kxm.model-inventory.v1`)
1222
1293
 
@@ -1287,7 +1358,7 @@ commands themselves are not counted.
1287
1358
  | `sync.jira.host`, `.projectKey`, `.issueType`, `.autoTransition` | String or boolean | none | Not read by any code path yet |
1288
1359
  | `improvement.promotionPolicy` | `manual_pr`, `critic_quorum`, or `auto_threshold`; any other value falls back to `manual_pr` | `manual_pr` | `kxm improve` (`cmdImprove` in `plugins/kxm/src/cli/system.ts`, then `evaluatePromotionPolicy` in `improve.ts`): selects the review-readiness rule reported per candidate. No value authorizes or activates anything |
1289
1360
  | `improvement.telemetryHalfLifeDays` | Number greater than 0 and at most 3650; otherwise `14` | `14` | `kxm improve`: the half-life of each record's weight in `weightedRecurrence`, which orders report rows and never decides candidacy |
1290
- | `improvement.autoThreshold.minRuns`, `.minPassRate`, `.minCostSavings` | `minRuns` an integer from 1 to 1,000,000, `minPassRate` from 0 to 1, `minCostSavings` at least 0; otherwise the default | `10`, `0.95`, `0.5` | `kxm improve`, only under `auto_threshold`: distinct runs, accepted share, and mean recorded cost per attempt a candidate needs to report ready for review. A group with no recorded cost is never ready |
1361
+ | `improvement.autoThreshold.minRuns`, `.minPassRate`, `.minCostSavings` | `minRuns` an integer from 1 to 1,000,000, `minPassRate` from 0 to 1, `minCostSavings` at least 0; otherwise the default | `10`, `0.95`, `0.5` | `kxm improve`, only under `auto_threshold` (see below) |
1291
1362
  | `routing.shadowExecution.enabled` | Boolean | `false` | Not read by any code path yet |
1292
1363
  | `routing.shadowExecution.sampleRate` | Number | `0.05` | Not read by any code path yet |
1293
1364
  | `routing.shadowExecution.candidateModels` | Array of strings | `[]` | Not read by any code path yet |
@@ -1297,6 +1368,11 @@ commands themselves are not counted.
1297
1368
  | `telemetry.anonymize` | Boolean | `true` | Not read by any code path yet |
1298
1369
  | `telemetry.userTelemetryDir` | Path | none | Not read by any code path yet |
1299
1370
 
1371
+ Under `auto_threshold`, `minRuns`, `minPassRate` and `minCostSavings` are the
1372
+ distinct runs, the accepted share, and the mean recorded cost per attempt a
1373
+ candidate needs before `kxm improve` reports it ready for review. A group with
1374
+ no recorded cost is never ready.
1375
+
1300
1376
  ```yaml
1301
1377
  # .kxm/config.yaml (project scope) or ~/.config/kxm/config.yaml (user scope).
1302
1378
  # Only hub.autoStart and improvement.* change behavior today.
@@ -1337,6 +1413,24 @@ Commands:
1337
1413
  There is no `kxm config unset`. Delete the key from the file to fall back to
1338
1414
  the next layer; setting `null` stores `null`.
1339
1415
 
1416
+ ### Configuration layers
1417
+
1418
+ Preferences resolve through three file layers, and environment variables configure the processes beside them without overriding any `kxm.config.v1` key.
1419
+
1420
+ ```mermaid
1421
+ flowchart LR
1422
+ D["Built-in defaults<br/>config.ts"] -->|"overridden by"| U["User layer<br/>~/.config/kxm/config.yaml"]
1423
+ U -->|"overridden by"| P["Project layer<br/>.kxm/config.yaml"]
1424
+ P --> V["Merged view<br/>kxm config list"]
1425
+ CU["kxm config set --scope user"] -->|writes| U
1426
+ CP["kxm config set<br/>(project scope, the default)"] -->|writes| P
1427
+ E["Environment variables<br/>KXM_*"] -.->|"KXM_USER_CONFIG_DIR moves it"| U
1428
+ E -->|"configure; never override these keys"| S["Hub, agent, worker<br/>and Runtime processes"]
1429
+ HB["kxm hub start<br/>kxm hub bind"] -->|"persist credentials and URL"| S
1430
+ ```
1431
+
1432
+ Values that `kxm hub start` and `kxm hub bind` persist on the machine (`hub-env.json` and `hub-binding.json` under the [state root](#state-outside-the-project)) apply only when the matching variable, such as `KXM_AUTH_TOKEN` or `KXM_SERVER_URL`, is unset. [Environment variables and limits](configuration.md#where-settings-come-from) lists every variable.
1433
+
1340
1434
  ## `.kxm/modes.yaml` (`kxm.modes.v1`)
1341
1435
 
1342
1436
  Modes for `kxm explain`, which estimates the prompt footprint and token cost of
@@ -1466,7 +1560,8 @@ Parser: `parseMemoryRecord` in `plugins/kxm/src/memory.ts`.
1466
1560
 
1467
1561
  - `.kxm/memory/*.md` (top level only) are authored facts. Only
1468
1562
  `lifecycle: active` facts appear in `kxm memory brief` and in the projection
1469
- that `kxm memory sync` writes into `AGENTS.md`, `CLAUDE.md`, and `GEMINI.md`.
1563
+ that `kxm memory sync` writes into whichever of `AGENTS.md`, `CLAUDE.md`, and
1564
+ `GEMINI.md` already exist; it never creates them.
1470
1565
  - `.kxm/memory/candidates/*.md` are candidates written by `kxm memory note`.
1471
1566
  Promote one by moving it into `.kxm/memory/` in a reviewed change.
1472
1567
  - Every file under `.kxm/memory/` except `candidates/` is hashed into the
@@ -1521,18 +1616,19 @@ Validated with `kxm memory brief --json`.
1521
1616
  Both directories are written by commands, not configured by hand.
1522
1617
 
1523
1618
  - `.kxm/skills/` holds the governed skill lifecycle:
1524
- `candidates/<id>/`, `promoted/<id>/`, `quarantined/<id>/`, and
1619
+ `candidates/<id>/`, `promoted/<id>/`, `quarantineds/<id>/` (the directory name
1620
+ the code uses for the `quarantined` state), and
1525
1621
  `rejected/<id>/`, each with `SKILL.md` and `metadata.json`
1526
1622
  (`kxm.skill-candidate.v1`), plus `history/<id>.jsonl`. Written by
1527
1623
  `kxm skills create|evaluate|promote|reject`; `kxm skills verify` detects
1528
1624
  out-of-band edits to promoted skills. Promoted skills are hashed into the
1529
- memory revision pinned on each run. See [Skills](skills.md).
1625
+ memory revision pinned on each run. See [Skills](../guides/governed-skills.md).
1530
1626
  - `.kxm/candidates/` holds improvement candidates (`<id>.json`,
1531
1627
  `kxm.candidate.v1`, with a proposed diff file) written by `kxm improve`
1532
1628
  (`--out-dir` relocates them; `--dry-run` writes none). The report itself goes to
1533
1629
  `<workspace>/assets/improvements/`. A candidate is a proposal: its diff has
1534
1630
  placeholder hunks, nothing applies it, and its promotion readiness never
1535
- authorizes. See [Continuous improvement](continuous-improvement.md#coded-repeats-kxm-improve).
1631
+ authorizes. See [Continuous improvement](../guides/continuous-improvement.md#coded-repeats-kxm-improve).
1536
1632
 
1537
1633
  ## Webhook workflow definitions
1538
1634
 
@@ -1548,114 +1644,14 @@ treated as legacy configuration and makes the whole project unloadable
1548
1644
  either; those are `kxm.workflow.v1` files and fail to parse as JSON. A path
1549
1645
  such as `.kxm/assets/webhooks/workflows.json` works.
1550
1646
 
1551
- | Field | Type and allowed values | Required, default |
1552
- |---|---|---|
1553
- | `id` | String, at most 64 characters, unique | Required; appears in `/v1/webhooks/<id>` |
1554
- | `source` | `jira`, `github`, or `generic` | `generic` |
1555
- | `project` | Hub project name, at most 128 characters | Required |
1556
- | `target` | Coordinator name or durable agent ID, at most 80 characters | Required |
1557
- | `secretEnv` or `secret` | Variable name, or the literal secret (at least 16 characters); exactly one | Required; prefer `secretEnv` |
1558
- | `signalSecretEnv` or `signalSecret` | Same rules, for result callbacks | Optional; callbacks fall back to the start secret |
1559
- | `event` | String, at most 128 characters | Optional provider event filter |
1560
- | `filter.path`, `filter.equals` | Dotted JSON path and exact string | Optional |
1561
- | `delivery` | `followUp` or `steer` | `followUp` |
1562
- | `ttlMs` | Integer, 1,000 to 604,800,000 | Optional |
1563
- | `promptTemplate` | String, at most 20,000 characters, with `{{payload.path}}` substitutions | Required |
1564
- | `maxTransitions` | Integer, 1 to 200 | Required when any stage has a back-edge |
1565
- | `planHash`, `reproOracle` | `{stageId, evidenceKey}` | Optional |
1566
- | `requirePlanHash` | Stage IDs | Optional |
1567
- | `stages` | 1 to 32 stages | Required |
1568
- | `stages[].id` | String, at most 64 characters, unique | Required |
1569
- | `stages[].label` | String, at most 128 characters | The stage ID |
1570
- | `stages[].instructions` | String, at most 4,000 characters | Required |
1571
- | `stages[].requiredEvidence` | Up to 32 strings, unique after trimming, collapsing whitespace, and lowercasing | `[]` |
1572
- | `stages[].maxAttempts` | Integer, 1 to 20 | `3` |
1573
- | `stages[].autoResumeLimit` | Integer, 1 to 20 | Optional |
1574
- | `stages[].area` | `harness`, `gates`, `implementation`, `workflow`, `documentation`, `security`, or `other` | Optional |
1575
- | `stages[].on` | Map of outcome to a stage ID, `$terminal`, or `{target, maxTransitions}` | Optional |
1576
- | `stages[].maxTransitions` | Integer, 1 to 100 | Optional |
1577
- | `stages[].evidencePolicies.<requirement>` | `{kind: peer-reply, minProducers (1 to 8), eligibleAgents (1 to 16), acceptedStatuses: [replied], degradation: {minProducers}}` | Optional; see [Peer provenance and quorum gates](provenance-gates.md) |
1578
-
1579
- Rules that differ from `kxm.workflow.v1`: a forward transition may only target
1580
- the next stage; `$terminal` takes no `terminalStatus`; an evidence policy key
1581
- must match a `requiredEvidence` entry, may not list the workflow `target` among
1582
- its eligible agents, and its degradation minimum must be lower than
1583
- `minProducers` (a degraded minimum below 2 is a warning). Unknown fields are
1584
- ignored rather than rejected, and errors are plain messages, not codes. The
1585
- secret variables must be set when the file is parsed.
1586
-
1587
- ```json
1588
- [
1589
- {
1590
- "id": "jira-development",
1591
- "source": "jira",
1592
- "project": "payments",
1593
- "target": "coordinator",
1594
- "secretEnv": "JIRA_WEBHOOK_SECRET",
1595
- "signalSecretEnv": "WORKFLOW_SIGNAL_SECRET",
1596
- "event": "jira:issue_updated",
1597
- "filter": { "path": "issue.fields.status.name", "equals": "In Progress" },
1598
- "delivery": "followUp",
1599
- "ttlMs": 86400000,
1600
- "maxTransitions": 6,
1601
- "planHash": { "stageId": "plan", "evidenceKey": "approved plan" },
1602
- "requirePlanHash": ["implement"],
1603
- "promptTemplate": "Deliver {{issue.key}}: {{issue.fields.summary}}",
1604
- "stages": [
1605
- {
1606
- "id": "plan",
1607
- "label": "Plan and review",
1608
- "instructions": "Produce a plan and collect two independent peer reviews.",
1609
- "requiredEvidence": ["approved plan", "peer reviews"],
1610
- "evidencePolicies": {
1611
- "peer reviews": {
1612
- "kind": "peer-reply",
1613
- "minProducers": 2,
1614
- "eligibleAgents": ["reviewer-claude", "reviewer-grok"],
1615
- "acceptedStatuses": ["replied"],
1616
- "degradation": { "minProducers": 1 }
1617
- }
1618
- },
1619
- "maxAttempts": 3,
1620
- "area": "workflow",
1621
- "on": { "passed": "implement" }
1622
- },
1623
- {
1624
- "id": "implement",
1625
- "label": "Implement",
1626
- "instructions": "Implement the approved plan.",
1627
- "requiredEvidence": ["diff"],
1628
- "maxAttempts": 3,
1629
- "autoResumeLimit": 2,
1630
- "area": "implementation",
1631
- "on": { "passed": "ci" }
1632
- },
1633
- {
1634
- "id": "ci",
1635
- "label": "Wait for CI",
1636
- "instructions": "Start kxm_workflow_wait and let kxm gate github watch report the checks.",
1637
- "requiredEvidence": ["github.check:ci"],
1638
- "maxAttempts": 3,
1639
- "area": "gates",
1640
- "on": {
1641
- "passed": "$terminal",
1642
- "failed": { "target": "implement", "maxTransitions": 2 }
1643
- },
1644
- "maxTransitions": 2
1645
- }
1646
- ]
1647
- }
1648
- ]
1649
- ```
1650
-
1651
- Validated with `kxm gate validate --file .kxm/assets/webhooks/workflows.json`
1652
- with both secret variables set (one warning, for the degraded minimum of 1).
1653
-
1654
- Commands: `kxm gate validate [--file <path>]` parses the active source without
1655
- printing secrets (exit 2 when no source or both variables are set); the hub
1656
- loads it on `kxm hub start`; `kxm workflow start`, `kxm gate signal`, and
1657
- `kxm gate github watch` resolve each definition's secret variables. See
1658
- [Webhook workflows](webhook-workflows.md).
1647
+ [Workflow definitions](workflow-definitions.md#webhook-workflow-definitions)
1648
+ documents every definition, stage and evidence-policy field, the transition
1649
+ rules, the limits, and a validated example. Check a file with
1650
+ `kxm gate validate --file <path>` (exit 2 when no source or both variables are
1651
+ set); the hub loads it on `kxm hub start`, and `kxm workflow start`,
1652
+ `kxm gate signal` and `kxm gate github watch` resolve each definition's secret
1653
+ variables. See [Webhook workflows](../guides/webhook-workflows.md) for a
1654
+ walk-through.
1659
1655
 
1660
1656
  ## Claude Code plugin settings
1661
1657
 
@@ -1666,17 +1662,22 @@ declares `userConfig` fields that Claude Code asks each user for. The plugin's
1666
1662
  | `userConfig` field | Environment variable | Required, default | Notes |
1667
1663
  |---|---|---|---|
1668
1664
  | `server_url` | `KXM_SERVER_URL` | Required, `http://127.0.0.1:7331` | The MCP server also falls back to that URL when empty |
1669
- | `auth_token` | `KXM_AUTH_TOKEN` | Optional; marked sensitive | Use the project token, never the admin token. When empty, the MCP server uses only this project's saved project token from the hub credential file (`hub-env.json`) and never falls back to the admin token; with neither, tool calls fail with a message naming the fix |
1665
+ | `auth_token` | `KXM_AUTH_TOKEN` | Optional; marked sensitive | Use the project token, never the admin token. See below for the fallback |
1670
1666
  | `agent_name` | `KXM_AGENT_NAME` | Required, `claude` | When empty, `claude-<pid>`. If another live session already holds the name, the server registers once more as `<name>-<pid>` |
1671
1667
  | `agent_purpose` | `KXM_AGENT_PURPOSE` | Required, `Claude Code implementation and review agent` | |
1672
1668
  | `project` | `KXM_PROJECT` | Optional | When empty, the `name` in `package.json` at the project directory, else the directory name |
1673
1669
  | (not a user field) | `KXM_PROJECT_DIR` | Set from `${CLAUDE_PROJECT_DIR}` | Used to derive the default project |
1674
1670
 
1671
+ When `auth_token` is empty, the MCP server uses only this project's saved
1672
+ project token from the hub credential file (`hub-env.json`) and never falls
1673
+ back to the admin token. With neither, tool calls fail with a message naming
1674
+ the fix.
1675
+
1675
1676
  The manifest also registers one `SessionStart` hook,
1676
1677
  `node ${CLAUDE_PLUGIN_ROOT}/dist/claude-hook.js session-start`, with a 5-second
1677
1678
  timeout. It runs only inside a KXM project, reads this project's state only,
1678
1679
  never mints a token or writes a file, and always exits 0. See the
1679
- [plugin README](../plugins/kxm/README.md) for what it adds to the session.
1680
+ [plugin README](../../plugins/kxm/README.md) for what it adds to the session.
1680
1681
 
1681
1682
  ## Updater settings (`kxm.update.v1`)
1682
1683
 
@@ -1715,16 +1716,18 @@ Everything under `.kxm/` at the project root falls into one of three groups.
1715
1716
  | `logs/` | Ignored runtime logs | The hub and workers |
1716
1717
  | `state/` | Ignored restart state: the hub database `kxm.db`, Pi sessions, worker manifests | The hub and workers |
1717
1718
  | `run/` | Ignored sockets (`run/ssh-sockets/`) | `kxm ssh` |
1719
+ | `backups/` | Ignored; each `backup-<time>/` holds a copy of the hub database and `manifest.json` | `kxm backup` (without `--out`) |
1718
1720
  | `config/` | Legacy: its JSON files make the project unloadable | Nothing current |
1719
1721
  | `.kxm-init-transaction/` (sibling of `.kxm/` at the Git root) | Ignored; interrupted `kxm init` state | `kxm init` |
1720
1722
 
1721
- The ignore rules the KXM repository itself uses, adapted for a project:
1723
+ Recommended ignore rules for a project, based on the ones the KXM repository uses plus `.kxm/backups/`:
1722
1724
 
1723
1725
  ```text
1724
1726
  .kxm/logs/*
1725
1727
  .kxm/state/*
1726
1728
  .kxm/tasks/
1727
1729
  .kxm/run/
1730
+ .kxm/backups/
1728
1731
  .kxm/assets/generated/
1729
1732
  .kxm-init-transaction/
1730
1733
  *.db
@@ -1735,7 +1738,8 @@ The ignore rules the KXM repository itself uses, adapted for a project:
1735
1738
  `KXM_WORKSPACE_DIR`, `KXM_LOGS_DIR`, `KXM_ASSETS_DIR`, `KXM_STATE_DIR`, and
1736
1739
  related variables move `logs/`, `assets/`, and `state/`. They do not move the
1737
1740
  configuration files, which always live under `<project root>/.kxm/`. See
1738
- [Configuration](configuration.md) and [Operations](operations.md).
1741
+ [Workspace directories](configuration.md#workspace-directories) and
1742
+ [Backup and restore](../operations/backup-and-restore.md).
1739
1743
 
1740
1744
  ### State outside the project
1741
1745
 
@@ -1941,3 +1945,10 @@ In a project that `kxm init` created,
1941
1945
  same shape (without the `requiredEvidence` entries), and `kxm run` prints the
1942
1946
  matching `kxm runs drive <runId> --simulated --wait` command for each run it
1943
1947
  creates.
1948
+
1949
+ ## Related
1950
+
1951
+ - [Environment variables and limits](configuration.md): hub, agent and worker settings
1952
+ - [Workflow definitions](workflow-definitions.md): webhook JSON and Runtime YAML side by side
1953
+ - [CLI reference](cli-reference.md): the commands that read and write these files
1954
+ - [Harness routing](harness-routing.md): choose and confirm a model route