@kontextmind/kxm 0.7.128 → 0.7.131
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.kxm/README.md +4 -1
- package/.kxm/agents/coordinator.yaml +1 -0
- package/.kxm/agents/critic-arch.yaml +1 -4
- package/.kxm/agents/critic-cli.yaml +1 -4
- package/.kxm/agents/implementer.yaml +1 -4
- package/.kxm/workflows/implement-only.yaml +1 -1
- package/.kxm/workflows/review-arch-only.yaml +1 -1
- package/.kxm/workflows/review-cli-only.yaml +1 -1
- package/CHANGELOG.md +42 -1
- package/docs/architecture/inventory.md +1 -1
- package/docs/concepts/architecture.md +1 -1
- package/docs/concepts/data-and-storage.md +1 -1
- package/docs/contracts/README.md +1 -1
- package/docs/contracts/migration.md +12 -8
- package/docs/contracts/routing.md +3 -3
- package/docs/contributing/assignment-runner.md +14 -15
- package/docs/contributing/development.md +22 -6
- package/docs/contributing/harness-routing-internals.md +8 -8
- package/docs/glossary.md +1 -1
- package/docs/guides/agent-skills.md +1 -1
- package/docs/operations/backup-and-restore.md +7 -7
- package/docs/operations/upgrade.md +2 -2
- package/docs/reference/cli-reference.md +37 -14
- package/docs/reference/config-reference.md +81 -155
- package/docs/reference/harness-routing.md +29 -21
- package/docs/reference/workflow-catalog.md +4 -4
- package/docs/start/first-workflow.md +1 -1
- package/examples/project/.kxm/agents/coordinator.yaml +1 -2
- package/examples/project/.kxm/agents/critic-1.yaml +1 -3
- package/examples/project/.kxm/agents/critic-2.yaml +1 -2
- package/examples/project/.kxm/agents/critic-3.yaml +2 -3
- package/examples/project/.kxm/agents/implementer.yaml +1 -2
- package/examples/project/.kxm/agents/planner.yaml +1 -2
- package/examples/project/.kxm/agents/reproducer.yaml +1 -2
- package/examples/project/.kxm/agents/reviewer.yaml +1 -2
- package/examples/project/.kxm/workflows/fix.yaml +0 -12
- package/package.json +8 -8
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +2565 -465
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/runtime-supervisor.js +683 -348
- package/plugins/kxm/dist/runtime.js +694 -358
- package/plugins/kxm/dist/server.js +17 -14
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/kxm/SKILL.md +1 -1
- package/plugins/kxm/skills/kxm-definitions/SKILL.md +8 -0
- package/plugins/kxm/src/cli/lanes.ts +109 -4
- package/plugins/kxm/src/cli/project.ts +6 -6
- package/plugins/kxm/src/database.ts +25 -19
- package/plugins/kxm/src/engine.ts +168 -163
- package/plugins/kxm/src/init-guide-setup.ts +75 -15
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/oneshot-producer.ts +3 -15
- package/plugins/kxm/src/project-config.ts +83 -70
- package/plugins/kxm/src/routes.ts +26 -18
- package/plugins/kxm/src/runtime-service.ts +1 -0
- package/plugins/kxm/src/runtime-store.ts +390 -77
- package/plugins/kxm/src/runtime-supervisor.ts +87 -21
- package/plugins/kxm/src/suggest.ts +2 -2
- package/plugins/kxm/src/template.ts +2 -14
- package/schemas/agent.schema.json +8 -0
- package/scripts/roster-policy.d.mts +2 -1
- package/scripts/roster-policy.mjs +119 -22
- package/scripts/run-bounded.mjs +53 -0
|
@@ -177,7 +177,7 @@ kxm init [--name <name>] [--project-id <id>] [--repository <id=absolute-path>]..
|
|
|
177
177
|
|
|
178
178
|
Creates, validates, repairs, resumes, or joins a KXM project at the Git root that contains the current directory. A new project gets a minimal configuration: one coordinator agent, one implementer agent, a `test` command gate, and a `default` plan-implement-verify workflow. An existing project is validated without rewriting. Conflict-free template updates to non-authority fields are applied; authority changes, overlapping edits, and provenance-free or legacy state stay planning-only. `init` does not start a hub or the Runtime.
|
|
179
179
|
|
|
180
|
-
The starter `defaultHarness: pi` and `npm test` gate are generic settings, not repository detection. Creation and create-planning output include `guidance`: for Claude, set `defaultHarness: claude` in `.kxm/project.yaml
|
|
180
|
+
The starter `defaultHarness: pi` and `npm test` gate are generic settings, not repository detection. Initialized agents bind roles. Harness, model, and effort are set in `.kxm/roles/*.yaml` and `.kxm/models/*.yaml`. Creation and create-planning output include `guidance`: for Claude, set `defaultHarness: claude` in `.kxm/project.yaml`; for .NET or other non-npm repositories, set `.kxm/gates.yaml` → `gates.test.argv` to the repository's actual test command. Preflight reports an actionable prerequisite for `npm test` without a readable `package.json` test script; `task run` refuses it before creating a run.
|
|
181
181
|
|
|
182
182
|
| Option | Argument | Default | Description |
|
|
183
183
|
|---|---|---|---|
|
|
@@ -393,7 +393,7 @@ kxm completion install --shell zsh --dry-run
|
|
|
393
393
|
|
|
394
394
|
Compares the authority-bearing fields of the project configuration against a base Git revision. The base is materialized into a temporary shadow with a sanitized environment; nothing in the project is written. Both subcommands refuse `--workspace` (exit 2) and need no hub.
|
|
395
395
|
|
|
396
|
-
The comparison covers the loaded bundle only: `project.yaml`, `agents/`, `models/`, `workflows/`, `gates.yaml`, `project/env.yaml`, and each member repository's `repo.yaml` and `env.yaml`. It does not read `routes.yaml`, `roles/`, `
|
|
396
|
+
The comparison covers the loaded bundle only: `project.yaml`, `agents/`, `models/`, `workflows/`, `gates.yaml`, `project/env.yaml`, and each member repository's `repo.yaml` and `env.yaml`. It does not read `routes.yaml`, `roles/`, `the role files`, or `prices.yaml`, so a new route admission, roster entry, developer policy route, or price change never counts as an expansion. Review those files by hand.
|
|
397
397
|
|
|
398
398
|
### `kxm trust diff`
|
|
399
399
|
|
|
@@ -1069,14 +1069,32 @@ Lists admitted and disabled routes.
|
|
|
1069
1069
|
|
|
1070
1070
|
No command-specific options.
|
|
1071
1071
|
|
|
1072
|
-
- Reads only. JSON keys: `policy` (`schema`, `updatedAt`, `admitted`, `disabled
|
|
1072
|
+
- Reads only. JSON keys: `policy` (`schema`, `updatedAt`, `admitted`, `disabled`) and `membership` (strings `<role> <route-id>` from `.kxm/roles/*.yaml`). `policy` has no `roles` field. A model file named by no roster, such as `opus-claude`, is absent from `membership`.
|
|
1073
1073
|
|
|
1074
1074
|
```bash
|
|
1075
1075
|
kxm routes list
|
|
1076
1076
|
```
|
|
1077
1077
|
|
|
1078
1078
|
```text
|
|
1079
|
-
|
|
1079
|
+
admitted anthropic/fable
|
|
1080
|
+
admitted google/gemini-3.8-flash-high
|
|
1081
|
+
admitted google/gemini-3.8-flash-medium
|
|
1082
|
+
admitted openai/gpt-5.6-sol
|
|
1083
|
+
admitted openrouter/qwen/qwen3-coder-plus
|
|
1084
|
+
admitted openrouter/qwen/qwen3.8-flash
|
|
1085
|
+
admitted openrouter/z-ai/glm-5.3-flash
|
|
1086
|
+
admitted qwen-token-plan/deepseek-v4.1-flash
|
|
1087
|
+
admitted qwen-token-plan/qwen3.8-flash
|
|
1088
|
+
admitted qwen-token-plan/qwen3.8-max
|
|
1089
|
+
admitted xai/grok-4.7
|
|
1090
|
+
admitted zai-coding-cn/glm-5.3
|
|
1091
|
+
admitted zai-coding-cn/glm-5.3-flash
|
|
1092
|
+
planner fable-claude
|
|
1093
|
+
reviewer-arch fable-claude
|
|
1094
|
+
reviewer-cli sol-codex
|
|
1095
|
+
writer grok-native
|
|
1096
|
+
writer qwen-openrouter-pi
|
|
1097
|
+
writer gemini-agy
|
|
1080
1098
|
```
|
|
1081
1099
|
|
|
1082
1100
|
```bash
|
|
@@ -1084,7 +1102,7 @@ kxm routes list --json
|
|
|
1084
1102
|
```
|
|
1085
1103
|
|
|
1086
1104
|
```text
|
|
1087
|
-
{"schema":"kxm.cli-result.v1","ok":true,"command":"routes list","policy":{"schema":"kxm.routes.v2","updatedAt":"2026-09-
|
|
1105
|
+
{"schema":"kxm.cli-result.v1","ok":true,"command":"routes list","policy":{"schema":"kxm.routes.v2","updatedAt":"2026-09-24T00:00:00.000Z","admitted":["anthropic/fable","google/gemini-3.8-flash-high","google/gemini-3.8-flash-medium","openai/gpt-5.6-sol","openrouter/qwen/qwen3-coder-plus","openrouter/qwen/qwen3.8-flash","openrouter/z-ai/glm-5.3-flash","qwen-token-plan/deepseek-v4.1-flash","qwen-token-plan/qwen3.8-flash","qwen-token-plan/qwen3.8-max","xai/grok-4.7","zai-coding-cn/glm-5.3","zai-coding-cn/glm-5.3-flash"],"disabled":[]},"membership":["planner fable-claude","reviewer-arch fable-claude","reviewer-cli sol-codex","writer grok-native","writer qwen-openrouter-pi","writer gemini-agy"]}
|
|
1088
1106
|
```
|
|
1089
1107
|
|
|
1090
1108
|
### `kxm routes count`
|
|
@@ -1217,7 +1235,7 @@ Adds a role definition. Without a role ID, or with `--pick`, local scope offers
|
|
|
1217
1235
|
|
|
1218
1236
|
- Writes `.kxm/roles/<id>.yaml` in local scope, or `<KXM_USER_CONFIG_DIR>/roles/<id>.yaml` in global scope. `--dry-run` plans the write and writes nothing.
|
|
1219
1237
|
- Each `--route` is checked the same way as `kxm role modify --add-route`. If `.kxm/models/<route-id>.yaml` is missing, the command exits 1 and writes `kxm: route '<route-id>' is not a file under .kxm/models/` to stderr. It does not write the role file, including under `--dry-run`. `--file` checks every `roster[].route` the same way before writing, in local scope and in global scope.
|
|
1220
|
-
- Local scope belongs to a KXM project: the file lands in the project root's `.kxm/roles/` from any subdirectory, and outside a project the command refuses with `project_not_found` and creates nothing. Before writing, the project loader checks the project with the new role in place of any file of that ID.
|
|
1238
|
+
- Local scope belongs to a KXM project: the file lands in the project root's `.kxm/roles/` from any subdirectory, and outside a project the command refuses with `project_not_found` and creates nothing. Before writing, the project loader checks the project with the new role in place of any file of that ID. Validation is the role file schema, and every roster route must exist under `.kxm/models/`. If the project would not load, the command refuses with `role_invalid`, lists each issue and writes nothing, also under `--dry-run`, and `--overwrite` replaces a role file the loader refuses. Global scope is not checked, because no loader reads it.
|
|
1221
1239
|
- Refusals exit 2 and honor `--json`: `project_not_found` and `role_invalid` (with `issues`, each `{phase, code, file, message}`). A missing `--route` file, and an existing role without `--overwrite`, exit 1 with a plain stderr line, also under `--dry-run` (`kxm: route '<route-id>' is not a file under .kxm/models/`, or `role add failed: role_already_exists: ...`).
|
|
1222
1240
|
- JSON keys: `roleId`, `id`, `filePath`, `scope`.
|
|
1223
1241
|
|
|
@@ -1345,7 +1363,7 @@ dry run: resume workflow run wf_dry_run (stage: review)
|
|
|
1345
1363
|
|
|
1346
1364
|
## `kxm lane`
|
|
1347
1365
|
|
|
1348
|
-
One lane is one git worktree, one branch named the unit, and one recorded base sha. The record lives in the control checkout's state directory, `.kxm/state/lanes.json` (`kxm.lanes.v1`, mode 0600). The worktree path is `../<control-dir-basename>-<unit>`, next to the control checkout. Creating a lane resolves the base ref to a sha and does not fetch. There is no push, merge, pull request, or branch delete. Selecting a lane sets the discovery cwd to that lane's path and rebuilds workspace directories from it; `KXM_WORKDIR` still selects the workspace root when it is set, so the lane path is the workspace root only when `KXM_WORKDIR` is unset.
|
|
1366
|
+
One lane is one git worktree, one branch named the unit, and one recorded base sha. The record lives in the control checkout's state directory, `.kxm/state/lanes.json` (`kxm.lanes.v1`, mode 0600). The worktree path is `../<control-dir-basename>-<unit>`, next to the control checkout. Creating a lane resolves the base ref to a sha and does not fetch. There is no push, merge, pull request, or branch delete. Selecting a lane sets the discovery cwd to that lane's path and rebuilds workspace directories from it; `KXM_WORKDIR` still selects the workspace root when it is set, so the lane path is the workspace root only when `KXM_WORKDIR` is unset. A lane worktree of an already registered repository registers in the Runtime registry under that project: the same project id, its own control root and event store, and the same home runtime. A foreign clone with the same id is refused with `project_home_conflict`.
|
|
1349
1367
|
|
|
1350
1368
|
```text
|
|
1351
1369
|
kxm lane create <unit> [--base <ref>]
|
|
@@ -1375,15 +1393,19 @@ Prints one line per lane: unit, branch, base sha, `dirty` (porcelain line count)
|
|
|
1375
1393
|
|
|
1376
1394
|
### `kxm lane status`
|
|
1377
1395
|
|
|
1378
|
-
The list row for one unit, plus `status` of `lastRunId` when the Runtime supervisor is already running and answers. Otherwise `status=unknown`. `kxm lane status` never starts the Runtime supervisor.
|
|
1396
|
+
The list row for one unit, plus `status` of `lastRunId` when the Runtime supervisor is already running and answers. Otherwise `status=unknown`. The text ends with `root=<path>`, the lane root that status read. JSON includes the same path as `root`. `kxm lane status` never starts the Runtime supervisor.
|
|
1379
1397
|
|
|
1380
1398
|
Refusals (exit 1): `lane_missing`, `lane_unit_invalid`, `lanes_unreadable`.
|
|
1381
1399
|
|
|
1382
1400
|
### `kxm lane drop`
|
|
1383
1401
|
|
|
1384
|
-
Removes the worktree and the record.
|
|
1402
|
+
Removes the worktree and the record, and unregisters that lane root from the Runtime registry. When the supervisor is running, drop calls `POST /v1/projects/unregister`. A stopped supervisor is not an error: drop takes the registry write lock, deletes the row when that transaction still sees no live supervisor, and continues when the registry is absent. If the lock finds a live supervisor, drop uses the unregister route instead of editing the file. The route answers 409 `runtime_project_busy` when that root has an unsettled run, and 409 `runtime_project_has_lanes` when the root is the home row and other lanes are still registered, unless the body sets `force` to true. Refuses `lane_dirty` when porcelain is nonempty. Refuses `lane_run_open` when any run in the lane event store is not `completed`, `failed`, or `cancelled`. The text names each unsettled run id, and JSON includes `runIds`. That list is the same read as `kxm runs list` when the supervisor is running, and a direct read of the lane event store when the supervisor is stopped. A lane with no event store keeps the earlier check: `lane_run_open` when `lastRunId` is set and that run is not settled. `--force` overrides both refusals and sends `force: true` on the unregister request. `git worktree remove --force` is used only with `--force`. The branch is not deleted; the text says so (`branchDeleted: false`). Unless `--force` is set, the `lastRunId` check may start the Runtime supervisor. The event-store list only attaches to a supervisor that is already running. `--dry-run` only attaches and does not unregister. `kxm lane status` never starts the supervisor.
|
|
1385
1403
|
|
|
1386
|
-
|
|
1404
|
+
`lane_run_open` also uses the detail `lane <unit> runs could not be read: <detail>` when the lane's project or store could not be read, so the drop fails closed and does not remove the worktree. `<detail>` is the error message, cut to 200 characters, or `run list failed` when the thrown value is not an `Error`. The unsettled-run details stay `lane <unit> run <ids> is unsettled` (with `runIds`) and `lane <unit> run <lastRunId> is <status>`.
|
|
1405
|
+
|
|
1406
|
+
`lane_unregister_failed` uses the detail `lane <unit> could not be unregistered: <detail>`. `<detail>` is cut to 300 characters. It appears when a live supervisor refused the unregister or the request failed: the error message, `lane root could not be unregistered` when the failure is not an `Error`, or `runtime supervisor is live but could not be reached` when the registry lock finds a live supervisor that drop cannot attach to.
|
|
1407
|
+
|
|
1408
|
+
Refusals (exit 1): `lane_missing`, `lane_dirty`, `lane_run_open`, `lane_git_failed`, `lane_unregister_failed`.
|
|
1387
1409
|
|
|
1388
1410
|
### `kxm lane run`
|
|
1389
1411
|
|
|
@@ -1638,8 +1660,8 @@ kxm runs status <runId> [--lane <unit>]
|
|
|
1638
1660
|
Show the projected status of a run, including durable drive receipt state (open / receipt verified / unsettled / orphaned).
|
|
1639
1661
|
|
|
1640
1662
|
- Arguments: `<runId>`, Run id. `--lane <unit>` discovers the project from that lane's worktree (`lane_missing` when the record or path is absent, `lane_unit_invalid` when the unit is not a KXM identifier, `lanes_unreadable` when the record cannot be read). Reads run state, but starts the supervisor if needed (not under `--dry-run`).
|
|
1641
|
-
- Text: `run <id>: <status> (workflow <id>, updated <time>)`, plus a drive line such as `drive <id>: open`, `completed (receipt verified)`, `unsettled <reason>`, `handoff`, `cancelled (<reason>)`, or `no receipt (orphaned)`.
|
|
1642
|
-
- JSON keys: `run` (`runId`, `status`, `workflowId`, `configRevision`, `updatedAt`, ...), `drive` (`driveId`, `mode`, `openedAt`, `receipt`, `verified`, `divergence`).
|
|
1663
|
+
- Text: `run <id>: <status> (workflow <id>, updated <time>)`, then `root <path>` (the checkout the status read, which is the lane worktree when `--lane` is set), plus a drive line such as `drive <id>: open`, `completed (receipt verified)`, `unsettled <reason>`, `handoff`, `cancelled (<reason>)`, or `no receipt (orphaned)`.
|
|
1664
|
+
- JSON keys: `projectRoot` (that same checkout), `run` (`runId`, `status`, `workflowId`, `configRevision`, `updatedAt`, ...), `drive` (`driveId`, `mode`, `openedAt`, `receipt`, `verified`, `divergence`).
|
|
1643
1665
|
- Errors: `project_required`, `run_status_failed`, `run_status_io_failed` (exit 1).
|
|
1644
1666
|
|
|
1645
1667
|
```bash
|
|
@@ -1648,6 +1670,7 @@ kxm runs status run_a80e84c98f514299b82f0157f4537ea3
|
|
|
1648
1670
|
|
|
1649
1671
|
```text
|
|
1650
1672
|
run run_a80e84c98f514299b82f0157f4537ea3: preparing (workflow default, updated 2026-09-23T17:47:29.682Z)
|
|
1673
|
+
root /work/proj
|
|
1651
1674
|
```
|
|
1652
1675
|
|
|
1653
1676
|
With no supervisor running:
|
|
@@ -1666,7 +1689,7 @@ kxm runs status --dry-run refused: the Runtime supervisor is not running and --d
|
|
|
1666
1689
|
kxm runs drive <runId> [--simulated] [--wait] [--timeout-ms <n>] [--lane <unit>]
|
|
1667
1690
|
```
|
|
1668
1691
|
|
|
1669
|
-
Opens a drive of the run. With `--simulated`, a model-free producer reports every agent step as passed. Without `--simulated` the drive runs in live mode: each agent step invokes its harness through a one-shot producer, and the agent's model must be an admitted route (otherwise `producer_route_not_admitted`; there is no fallback model). A read-only step runs with the harness's read-only flags. A step with `write` access runs with an audited writer profile, which only `pi` and `grok` have; it must be a single assignment in a project whose `limits.maxConcurrentRuns` is 1, and
|
|
1692
|
+
Opens a drive of the run. With `--simulated`, a model-free producer reports every agent step as passed. Without `--simulated` the drive runs in live mode: each agent step invokes its harness through a one-shot producer, and the agent's model must be an admitted route (otherwise `producer_route_not_admitted`; there is no fallback model). A read-only step runs with the harness's read-only flags. A step with `write` access runs with an audited writer profile, which only `pi` and `grok` have; it must be a single assignment in a project whose `limits.maxConcurrentRuns` is 1, and its route must be on the writer roster in `.kxm/roles/writer.yaml`. Otherwise the drive hands the run off with `step_unsupported`. Around each live attempt the Runtime fingerprints the checkout with `git status` and `git diff`: a write step settles `passed` only when the checkout changed (routing metadata `authored: true`), and a read-only step that changed it settles `failed` (`authoringWitness: readonly_mutated`).
|
|
1670
1693
|
|
|
1671
1694
|
| Option | Argument | Default | Description |
|
|
1672
1695
|
|---|---|---|---|
|
|
@@ -2838,7 +2861,7 @@ Recommends a flat workflow ID backed by a shipped template, with category metada
|
|
|
2838
2861
|
|
|
2839
2862
|
- Explicit `Claude only`, `Claude-only`, or `only Claude Code` constraints exclude other harnesses. A missing, unauthenticated, or unsupported required harness produces `harness_unavailable`; KXM never silently substitutes Grok or Codex.
|
|
2840
2863
|
- A write workflow requires an audited writer profile for the selected harness. Only Pi and Grok currently have one; Claude-only bug fixes produce `live_write_unsupported` with direct-Claude implementation guidance, never a Grok substitution. No misleading create/drive command is emitted for an unsupported profile.
|
|
2841
|
-
- For supported work, every suggested agent binding uses the selected detected, authenticated, dispatch-ready harness. Configure its compatible admitted model, install the exact template, validate project configuration, then use the separate create/live-drive/status/receipt commands. Writers also require single-assignment/single-run admission, any configured developer
|
|
2864
|
+
- For supported work, every suggested agent binding uses the selected detected, authenticated, dispatch-ready harness. Configure its compatible admitted model, install the exact template, validate project configuration, then use the separate create/live-drive/status/receipt commands. Writers also require single-assignment/single-run admission, any configured developer policy writer approval, and the repository's actual verification gate. An already-present recommended workflow ID produces `workflow_already_exists`; KXM will not assume its agents or permissions match the template.
|
|
2842
2865
|
- Arguments: `<prompt...>`; no command-specific options. No hub needed. `--dry-run` skips native authentication probes to avoid their side effects and does not claim verified availability.
|
|
2843
2866
|
- JSON keys: `prompt`, `workflowId`, `template`, `area`, `confidence`, `reasons`, `suggestedSkills`, `roles` (an array of `{agent, harness, role}`), `suggestedCommand` (installation only), and `execution`. Supported execution includes `prerequisites`, `shell`, `createCommand`, `driveCommand`, `statusCommand`, and `receiptCommand`; refusal includes `error`, `reason`, and `nextSteps`, sets `ok: false`, and exits 1.
|
|
2844
2867
|
|
|
@@ -25,13 +25,12 @@ Related pages:
|
|
|
25
25
|
| `.kxm/project.yaml` | `kxm.project.v1` | Project identity, repositories, defaults, run limits | You; `kxm init` creates it | Yes |
|
|
26
26
|
| `.kxm/repo/repo.yaml` (in each repository) | `kxm.repository.v1` | Per-repository definition | You; `kxm init` creates the control one | Yes, in the repository it describes |
|
|
27
27
|
| `.kxm/project/env.yaml`, `.kxm/repo/env.yaml` | `kxm.environment.v1` | Portable, non-secret environment | You | Yes |
|
|
28
|
-
| `.kxm/agents/<id>.yaml` | `kxm.agent.v1` | Agent
|
|
28
|
+
| `.kxm/agents/<id>.yaml` | `kxm.agent.v1` | Agent role and permission ceilings | You; `kxm init` creates two | Yes |
|
|
29
29
|
| `.kxm/models/<id>.yaml` | `kxm.model.v2` | One model route (harness, vendor, status, permissions) | You; `kxm init` | Yes |
|
|
30
30
|
| `.kxm/workflows/<id>.yaml` | `kxm.workflow.v1` | Ordered steps and typed transitions | You; `kxm init` creates `default` | Yes |
|
|
31
31
|
| `.kxm/gates.yaml` | `kxm.gate-registry.v1` | The executable gate registry | You; `kxm init` creates it | Yes |
|
|
32
32
|
| `.kxm/roles/<role>.yaml` | `kxm.role.v2` | Model rosters per role | You, `kxm role`, `kxm models` | Yes |
|
|
33
33
|
| `.kxm/routes.yaml` | `kxm.routes.v2` | Admitted and disabled model routes | You, `kxm routes`, `kxm models` | Yes |
|
|
34
|
-
| `.kxm/roster.yaml` | `kxm.developer-roster.v1` | Developer assignment roster for the KXM source repository | Maintainers | Yes, and it must be committed |
|
|
35
34
|
| `.kxm/prices.yaml` | `kxm.prices.v1` | Dated, hash-pinned list prices | You | Yes |
|
|
36
35
|
| `.kxm/models/inventory.yaml` | `kxm.model-inventory.v1` | Discovered model catalog | `kxm models inventory-refresh` only | Your choice (generated) |
|
|
37
36
|
| `.kxm/config.yaml`, `~/.config/kxm/config.yaml` | `kxm.config.v1` | Personalization and hub auto-start | `kxm config set` | Project file: yes, unless ignored |
|
|
@@ -44,6 +43,8 @@ Related pages:
|
|
|
44
43
|
| Claude Code plugin `userConfig` | Claude plugin manifest | Hub URL, token, agent identity for Claude Code | Claude Code, per user | No |
|
|
45
44
|
| `<state root>/update.yaml` | `kxm.update.v1` | Updater settings | You | No (host-local) |
|
|
46
45
|
|
|
46
|
+
The developer assignment runner reads `.kxm/roles/*.yaml` and `.kxm/models/*.yaml` at `refs/remotes/origin/main`.
|
|
47
|
+
|
|
47
48
|
`kxm init` does not write a `.gitignore`. See
|
|
48
49
|
[Workspace layout](#workspace-layout-tracked-ignored-and-state) for the entries
|
|
49
50
|
to add.
|
|
@@ -57,17 +58,16 @@ to add.
|
|
|
57
58
|
.kxm/workflows/<id>.yaml ── coordinator ──> .kxm/agents/coordinator.yaml
|
|
58
59
|
│ steps[]
|
|
59
60
|
├─ kind agent | moa | approval | wait ──> .kxm/agents/<id>.yaml
|
|
60
|
-
│ ├─
|
|
61
|
-
│
|
|
62
|
-
│ │
|
|
61
|
+
│ ├─ role ──> .kxm/roles/<role>.yaml
|
|
62
|
+
│ │ └─ roster[].route ──> .kxm/models/<route>.yaml
|
|
63
|
+
│ │ (harness, model, vendor, permissions)
|
|
63
64
|
│ └─ tools, repositories, network: permission ceilings
|
|
64
65
|
└─ kind gate ──> .kxm/gates.yaml: command | artifacts-exist | reserved
|
|
65
66
|
|
|
66
67
|
Live dispatch admission (checked by the Runtime for every attempt):
|
|
67
|
-
agent
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
developer assignments (scripts/assignment-run.mjs) ──> .kxm/roster.yaml routes + lineup
|
|
68
|
+
agent.role ──> .kxm/roles/<role>.yaml roster ──> .kxm/models/<route>.yaml
|
|
69
|
+
.kxm/routes.yaml holds only the admitted and disabled lists
|
|
70
|
+
developer assignments (scripts/assignment-run.mjs) ──> .kxm/roles/*.yaml and .kxm/models/*.yaml
|
|
71
71
|
|
|
72
72
|
Cost accounting:
|
|
73
73
|
producer token usage ──> .kxm/prices.yaml (dated today, hash verified) ──> list estimate
|
|
@@ -79,13 +79,14 @@ Cost accounting:
|
|
|
79
79
|
| Check | Files it covers | Where it runs |
|
|
80
80
|
|---|---|---|
|
|
81
81
|
| Project bundle load: restricted YAML, JSON Schema, cross-file semantics | `project.yaml`, every `repo.yaml` and `env.yaml`, `agents/`, `models/`, `workflows/`, `gates.yaml`, `template-provenance.yaml`, plus the `roles/writer.yaml` cross-check | `kxm init` (validate mode), `kxm run` and `kxm run --dry-run`, `kxm trust`, every Runtime request |
|
|
82
|
+
| Retired agent routing fields | `harness` or `model` on `.kxm/agents/<id>.yaml` | Loader refuses the file with `retired_agent_routing_fields` (`routing resolves from role; remove model and harness`) |
|
|
82
83
|
| Workflow compile | `workflows/` | `kxm run` when it creates a run |
|
|
83
|
-
| Runtime acceptance | Workflow steps, gate definitions,
|
|
84
|
+
| Runtime acceptance | Workflow steps, gate definitions, the route selected from `agent.role`, `routes.yaml` (`admitted` and `disabled` only), `roles/` | `kxm runs drive` and live drives, per step |
|
|
84
85
|
| Permission diff | The bundle only | `kxm trust diff`, `kxm trust check` |
|
|
85
86
|
| Revisions pinned on every run | `configRevision` (the bundle), memory revision (`.kxm/memory` without `candidates/`, plus `.kxm/skills/promoted`), executor policy, tool policy (agent and step `tools` plus the gate registry) | `kxm run` |
|
|
86
87
|
|
|
87
88
|
Nothing validates `routes.yaml`, `roles/` (other than `writer.yaml`),
|
|
88
|
-
`roles`, `
|
|
89
|
+
`roles`, `the role files`, `prices.yaml`, `inventory.yaml`,
|
|
89
90
|
`config.yaml`, `modes.yaml`, memory, tasks, goals, or webhook JSON during
|
|
90
91
|
`kxm init`. Their own readers report problems when they run. None of them are
|
|
91
92
|
part of `configRevision`, and `kxm trust check` does not see them: a change to
|
|
@@ -147,7 +148,7 @@ makes a directory a KXM project. Parser: `loadKxmProject` in
|
|
|
147
148
|
| `description` | String, at most 2,000 characters | Optional | Display only |
|
|
148
149
|
| `defaultWorkflow` | Identifier | Optional, `default` | Loader only: the named workflow must exist (`default_workflow_unknown`). `kxm run` always takes an explicit workflow. |
|
|
149
150
|
| `defaultExecutor` | `local`, `ssh`, or `exe-dev` | Optional | Loader (`executor_unknown`); recorded in the run's executor-policy revision |
|
|
150
|
-
| `defaultHarness` | `pi`, `claude`, `codex`, `grok`, `agy`, `kimi`, or `deepseek` | Optional, `pi` | Loader (`harness_unknown`); harness
|
|
151
|
+
| `defaultHarness` | `pi`, `claude`, `codex`, `grok`, `agy`, `kimi`, or `deepseek` | Optional, `pi` | Loader (`harness_unknown`); project default harness. An agent file does not set `harness`; that field is `retired_agent_routing_fields`. |
|
|
151
152
|
| `repositories` | Array of 1 to 64 entries | Required | Loader, Runtime |
|
|
152
153
|
| `repositories[].id` | Identifier | Required | Must be unique after case folding (`repository_id_collision`) |
|
|
153
154
|
| `repositories[].role` | `control` or `member` | Required | Exactly one `control` (`control_repository_count`) |
|
|
@@ -166,8 +167,11 @@ makes a directory a KXM project. Parser: `loadKxmProject` in
|
|
|
166
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 |
|
|
167
168
|
| `limits.agentStepTimeoutMs` | Integer, 60,000 to 31,536,000,000 | Optional, 3,600,000 | Wall clock for one live agent or moa step when the step omits `timeoutMs`. The supervisor passes it to the one-shot producer. A step `timeoutMs` narrower than this wins; a wider step value is refused (`step_unsupported`, field `timeoutMs`) |
|
|
168
169
|
|
|
169
|
-
The Runtime binds
|
|
170
|
-
|
|
170
|
+
The Runtime binds a project `id` to one repository. A git worktree of that
|
|
171
|
+
repository registers as a lane: the same id, its own control root, and the
|
|
172
|
+
same home runtime. A foreign clone with the same id is refused with
|
|
173
|
+
`project_home_conflict`. A registered root whose directory is gone is replaced
|
|
174
|
+
when a new root for that id registers.
|
|
171
175
|
|
|
172
176
|
Example (validated with `kxm init --json`, including a nested member checkout
|
|
173
177
|
at `repositories/api`):
|
|
@@ -319,15 +323,21 @@ One file per agent; the filename is the agent ID that workflow steps
|
|
|
319
323
|
reference. Schema: `schemas/agent.schema.json`; semantic checks in
|
|
320
324
|
`validateBundle` in `plugins/kxm/src/project-config.ts`.
|
|
321
325
|
|
|
326
|
+
An agent does not name a harness or a model. Routing starts at the agent's
|
|
327
|
+
`role`, continues through `.kxm/roles/<role>.yaml`, and uses the selected
|
|
328
|
+
`.kxm/models/<route>.yaml`. `harness` and `model` on an agent file fail load
|
|
329
|
+
with `retired_agent_routing_fields`.
|
|
330
|
+
|
|
322
331
|
| Field | Type and allowed values | Required, default | What reads it |
|
|
323
332
|
|---|---|---|---|
|
|
324
333
|
| `schema` | `kxm.agent.v1` | Required | Loader |
|
|
325
334
|
| `purpose` | String, 1 to 2,000 characters | Required | Display; neutral in `kxm trust` |
|
|
335
|
+
| `role` | Identifier | Optional | Loader: `.kxm/roles/<role>.yaml`, then the selected `.kxm/models/<route>.yaml` |
|
|
336
|
+
| `effort` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, or `max` | Optional | Recorded on the agent. Dispatch effort comes from the attempt, not this field. |
|
|
337
|
+
| `skills` | Unique identifiers, at most 64 | Optional | Skill names granted to the agent |
|
|
326
338
|
| `instructions` | String, at most 16,000 characters | Optional | Not read by any code path yet. Step `instructions` are what reach the prompt. |
|
|
327
|
-
| `harness` | `pi`, `claude`, `codex`, `grok`, `agy`, `kimi`, or `deepseek` | Optional, the project's `defaultHarness` | Loader (`harness_unknown`, harness and model pairing); live dispatch launches this harness |
|
|
328
|
-
| `model` | One selector: `{provider, model}`, `{profile}`, or `{tag, capabilities}` | Optional | See [Model selectors](#model-selectors) |
|
|
329
339
|
| `executor` | `local`, `ssh`, or `exe-dev` | Optional | Loader (`executor_unknown`); recorded in the executor-policy revision; no dispatch path selects an executor from it yet |
|
|
330
|
-
| `tools.preset` | `coordinator`, `read-only`, `workspace-writer`, or `tests-writer` | Optional | Loader (`tool_preset_unknown`)
|
|
340
|
+
| `tools.preset` | `coordinator`, `read-only`, `workspace-writer`, or `tests-writer` | Optional | Loader (`tool_preset_unknown`): the preset must be registered. An agent `tools.preset` may only narrow the role preset. Enforcement of that rule is pending (P3). |
|
|
331
341
|
| `tools.allow`, `tools.deny` | Unique identifiers, at most 128 each | Optional | A tool in both lists is `tool_policy_contradiction`; steps may only narrow the ceiling |
|
|
332
342
|
| `defaultRepositoryAccess` | `none`, `read`, or `write` | Optional; the ceiling is `none` when absent | Loader: access ceiling for repositories not listed in `repositories` |
|
|
333
343
|
| `repositories` | Map of repository ID to `none`, `read`, or `write`; at most 64 | Optional | Loader: per-repository access ceiling; IDs must be declared (`repository_unknown`) |
|
|
@@ -340,80 +350,24 @@ reference. Schema: `schemas/agent.schema.json`; semantic checks in
|
|
|
340
350
|
| `session.maxIdleMs` | Integer, 0 to 31,536,000,000 | Optional | Not read by any code path yet |
|
|
341
351
|
|
|
342
352
|
Tool presets are names checked against a registered list. The live one-shot
|
|
343
|
-
producer launches
|
|
344
|
-
translate `tools` into harness flags. A read-only
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
for `pi` (`-a` with
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
353
|
+
producer launches the harness named by the selected model file, with a fixed
|
|
354
|
+
argument set, and does not translate `tools` into harness flags. A read-only
|
|
355
|
+
step uses the read-only set (`READ_ONLY_ONESHOT_ARGS` in
|
|
356
|
+
`plugins/kxm/src/harness.ts`). A step with `write` access uses the audited
|
|
357
|
+
writer set (`WRITER_ONESHOT_ARGS`), which exists only for `pi` (`-a` with
|
|
358
|
+
extensions, skills, prompt templates and sessions off) and `grok`
|
|
359
|
+
(`--always-approve` with subagents and web search off). Both approve every
|
|
360
|
+
tool call, shell commands included, and neither confines the process to the
|
|
361
|
+
checkout. A live write step on any other harness is handed off; see
|
|
351
362
|
[Steps the Runtime does not execute yet](#steps-the-runtime-does-not-execute-yet).
|
|
352
363
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
A selector has exactly one of three shapes (`common.schema.json#/$defs/modelSelector`):
|
|
356
|
-
|
|
357
|
-
| Shape | Fields | Resolves to |
|
|
358
|
-
|---|---|---|
|
|
359
|
-
| Direct | `provider` (identifier), `model` (1 to 200 characters) | That provider and model. The route string is `provider/model`, for example `openrouter/qwen/qwen3-coder-plus`. |
|
|
360
|
-
| Profile | `profile` (identifier) | `.kxm/models/<profile>.yaml` (`model_profile_unknown` if missing) |
|
|
361
|
-
| Tag | `tag` (identifier), optional `capabilities` (identifiers) | Every profile carrying the tag and all listed capabilities (`model_tag_unresolved` if none) |
|
|
362
|
-
|
|
363
|
-
For live dispatch, only the direct shape works. The Runtime reads the agent's
|
|
364
|
-
`model.provider` and `model.model` and joins them into the route string; a
|
|
365
|
-
profile or tag selector validates at load time but live dispatch refuses the
|
|
366
|
-
step with `producer_route_unsupported: invalid model declaration`. An agent
|
|
367
|
-
with no model is refused too, except that an agent named `implementer`
|
|
368
|
-
without a model falls back to `xai/grok-4.6`.
|
|
369
|
-
|
|
370
|
-
### Harness and model pairing
|
|
371
|
-
|
|
372
|
-
The loader checks that the agent's harness can host its model, using
|
|
373
|
-
`validateHarnessModelPair` in `plugins/kxm/src/harness.ts`. It applies this
|
|
374
|
-
check only to models reached through a profile or tag selector. A direct
|
|
375
|
-
`{provider, model}` selector is not checked at load time; the live producer
|
|
376
|
-
checks it when it probes the harness before dispatch.
|
|
377
|
-
|
|
378
|
-
| Harness | Accepts |
|
|
379
|
-
|---|---|
|
|
380
|
-
| `claude` | Provider `anthropic`; rejects model IDs starting with `gpt-`, `o1-`, `o3-`, `grok-`, `gemini-`, `kimi-`, `moonshot-`, `deepseek-`, or `qwen-` |
|
|
381
|
-
| `codex` | Provider `openai`; rejects `claude-`, `fable-`, `grok-`, `gemini-`, `kimi-`, `moonshot-`, `deepseek-`, and `qwen-` models |
|
|
382
|
-
| `grok` | Provider `xai` and `grok-` models |
|
|
383
|
-
| `agy` | Provider `google` and `gemini-` models |
|
|
384
|
-
| `kimi` | Provider `moonshot` and `kimi`, `moonshot`, or `kimi-for-coding` models |
|
|
385
|
-
| `deepseek` | Provider `deepseek` and `deepseek-` models |
|
|
386
|
-
| `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) |
|
|
387
|
-
|
|
388
|
-
A mismatch is reported as `harness_unhosted_model`. Which route to choose for a
|
|
389
|
-
model that more than one harness can reach is covered in
|
|
390
|
-
[Harness routing](harness-routing.md).
|
|
391
|
-
|
|
392
|
-
### Live dispatch requirements
|
|
393
|
-
|
|
394
|
-
Before a live attempt, the Runtime (`resolveProducerRoute` in
|
|
395
|
-
`plugins/kxm/src/engine.ts`) requires all of the following. A failure hands the
|
|
396
|
-
run off with `step_unsupported` and a `producer_route_unsupported` detail.
|
|
397
|
-
|
|
398
|
-
1. The agent declares a direct `{provider, model}` selector (see above).
|
|
399
|
-
2. `provider/model` is listed in `.kxm/routes.yaml` `admitted` and not in
|
|
400
|
-
`disabled`.
|
|
401
|
-
3. If `.kxm/roles/<role>.yaml` exists, its roster contains exactly
|
|
402
|
-
`provider/model`. The role is the agent ID, except that agent
|
|
403
|
-
`implementer` maps to role `writer`.
|
|
404
|
-
|
|
405
|
-
Example (validated with `kxm init --json`):
|
|
364
|
+
Example (the shape `kxm init` writes for `implementer`):
|
|
406
365
|
|
|
407
366
|
```yaml
|
|
408
|
-
# .kxm/agents/implementer.yaml
|
|
367
|
+
# .kxm/agents/implementer.yaml. The filename is the agent id.
|
|
409
368
|
schema: kxm.agent.v1
|
|
410
369
|
purpose: Implement the approved change within the declared repository scope.
|
|
411
|
-
|
|
412
|
-
harness: grok # pi | claude | codex | grok | agy | kimi | deepseek
|
|
413
|
-
model: # direct selector: provider + model
|
|
414
|
-
provider: xai
|
|
415
|
-
model: grok-4.6
|
|
416
|
-
executor: local # local | ssh | exe-dev
|
|
370
|
+
role: writer # .kxm/roles/writer.yaml -> .kxm/models/<route>.yaml
|
|
417
371
|
tools:
|
|
418
372
|
preset: workspace-writer # coordinator | read-only | workspace-writer | tests-writer
|
|
419
373
|
allow: [read, edit, write, bash]
|
|
@@ -421,47 +375,26 @@ tools:
|
|
|
421
375
|
defaultRepositoryAccess: none # ceiling for repositories not listed below
|
|
422
376
|
repositories:
|
|
423
377
|
control: write
|
|
424
|
-
api: write
|
|
425
378
|
secrets:
|
|
426
379
|
- ref: npm-token # secret reference name
|
|
427
380
|
as: NPM_TOKEN # environment variable name inside the attempt
|
|
428
381
|
required: false
|
|
429
382
|
network: provider-only # none | provider-only | restricted | host
|
|
430
383
|
resultSchema: kxm.assignment-result.v1
|
|
431
|
-
session:
|
|
432
|
-
reuse: compatible-run-scope
|
|
433
|
-
maxIdleMs: 1800000
|
|
434
384
|
```
|
|
435
385
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
profile: critic-claude # profile selector: .kxm/models/critic-claude.yaml
|
|
444
|
-
tools:
|
|
445
|
-
preset: read-only
|
|
446
|
-
defaultRepositoryAccess: read
|
|
447
|
-
network: provider-only
|
|
448
|
-
resultSchema: kxm.assignment-result.v1
|
|
449
|
-
```
|
|
386
|
+
`kxm init` creates `coordinator` (`role: planner`) and `implementer`
|
|
387
|
+
(`role: writer`) without `harness` or `model`, and admits `anthropic/fable`
|
|
388
|
+
and `xai/grok-4.6` in `.kxm/routes.yaml`. An interactive `kxm init` can add
|
|
389
|
+
workflow-guide agents for reviewed pairs whose harness is authenticated, and
|
|
390
|
+
admits their selectors too, but skips Google guide candidates because the
|
|
391
|
+
Runtime cannot reach the `antigravity` Pi provider yet. `kxm run` and the
|
|
392
|
+
Runtime read the agents. `kxm trust` diffs them.
|
|
450
393
|
|
|
451
|
-
Error codes: `
|
|
452
|
-
`tool_policy_contradiction`, `repository_unknown`,
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
[Rules shared by the project bundle](#rules-shared-by-the-project-bundle), and
|
|
456
|
-
`role_roster_conflicts_with_agent` (see [Roles](#kxmrolesroleyaml-kxmrolev2)).
|
|
457
|
-
|
|
458
|
-
Commands: `kxm init` creates `coordinator` (`claude`, `anthropic/fable`) and
|
|
459
|
-
`implementer` (`grok`, `xai/grok-4.6`) and admits both selectors in
|
|
460
|
-
`.kxm/routes.yaml`; an interactive `kxm init` can add workflow-guide agents for
|
|
461
|
-
reviewed harness/model pairs whose harness is authenticated, and admits their
|
|
462
|
-
selectors too, but skips Google guide candidates because the Runtime cannot
|
|
463
|
-
reach the `antigravity` Pi provider yet; `kxm run` and the Runtime read them;
|
|
464
|
-
`kxm trust` diffs them.
|
|
394
|
+
Error codes: `retired_agent_routing_fields`, `executor_unknown`,
|
|
395
|
+
`tool_preset_unknown`, `tool_policy_contradiction`, `repository_unknown`, and
|
|
396
|
+
the path codes under
|
|
397
|
+
[Rules shared by the project bundle](#rules-shared-by-the-project-bundle).
|
|
465
398
|
|
|
466
399
|
## `.kxm/models/<id>.yaml` (`kxm.model.v2`)
|
|
467
400
|
|
|
@@ -500,11 +433,11 @@ status: admitted
|
|
|
500
433
|
permissions:
|
|
501
434
|
- edit
|
|
502
435
|
origin:
|
|
503
|
-
source:
|
|
504
|
-
sha256:
|
|
436
|
+
source: docs/reference/harness-routing.md
|
|
437
|
+
sha256: 321c821ed6dbce7b2e98309fdc29387671577049619b6979c685a7ba60c63337
|
|
505
438
|
```
|
|
506
439
|
|
|
507
|
-
Commands: `kxm init`, `kxm run`, and `kxm trust` load these files. `kxm role modify --add-route` refuses a route id that has no file here (exit 1). Dispatch membership for a role reads `harness`, `model`, and `vendor`. The developer assignment runner
|
|
440
|
+
Commands: `kxm init`, `kxm run`, and `kxm trust` load these files. `kxm role modify --add-route` refuses a route id that has no file here (exit 1). Dispatch membership for a role reads `harness`, `model`, and `vendor`. The developer assignment runner reads `.kxm/roles/*.yaml` and `.kxm/models/*.yaml` at `refs/remotes/origin/main`.
|
|
508
441
|
|
|
509
442
|
## `.kxm/workflows/<id>.yaml` (`kxm.workflow.v1`)
|
|
510
443
|
|
|
@@ -692,9 +625,8 @@ these, the run is handed off (`step_unsupported`, `gate_unsupported`, or
|
|
|
692
625
|
- A live (non-simulated) step with `write` access to any repository when its
|
|
693
626
|
agent's harness has no audited writer profile (only `pi` and `grok` have
|
|
694
627
|
one), when `assignments.maximum` is above 1, when the project's
|
|
695
|
-
`limits.maxConcurrentRuns` is above 1, or when `.kxm/
|
|
696
|
-
|
|
697
|
-
and model with `edit` permission. The checkout witness can attribute a
|
|
628
|
+
`limits.maxConcurrentRuns` is above 1, or when `.kxm/roles/writer.yaml` does not
|
|
629
|
+
admit that route with `edit` permission. The checkout witness can attribute a
|
|
698
630
|
change only to one writer at a time.
|
|
699
631
|
- Gate steps with `assignments.allowedAgents`, any assignment count or
|
|
700
632
|
`maxAttemptsPerAssignment` other than 1, `distinctBy`,
|
|
@@ -962,12 +894,10 @@ not this registry.
|
|
|
962
894
|
One role. The filename is the role id. `kxm config` validation checks the file
|
|
963
895
|
against `schemas/role.schema.json`.
|
|
964
896
|
|
|
965
|
-
`listRoleBindings` reads `roster[].route`.
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
against the `implementer` agent's model, or the `writer` agent when there is
|
|
970
|
-
no implementer. `kxm role` reads and writes these files. A file without
|
|
897
|
+
`listRoleBindings` reads `roster[].route`. An agent binds `role`, and dispatch
|
|
898
|
+
resolves harness, model, and effort from that role's roster and the matching
|
|
899
|
+
`.kxm/models/<route-id>.yaml` (`model`, `vendor/model`, or `harness/model`).
|
|
900
|
+
`kxm role` reads and writes these files. A file without
|
|
971
901
|
`schema: kxm.role.v2` is skipped by `kxm role`. A local file overrides a
|
|
972
902
|
global one with the same id.
|
|
973
903
|
|
|
@@ -989,9 +919,10 @@ global one with the same id.
|
|
|
989
919
|
| `policy.vendorIndependenceRequired`, `policy.maxTransitions`, `policy.requiresGateVerification` | Boolean, or a positive integer for `maxTransitions` | Optional | Recorded on the role |
|
|
990
920
|
|
|
991
921
|
Roster order is preference. `kxm role list` shows the first route as the
|
|
992
|
-
primary. The Runtime checks membership.
|
|
993
|
-
the agent
|
|
994
|
-
|
|
922
|
+
primary. The Runtime checks membership. Harness, model, and effort resolve
|
|
923
|
+
from the agent's `role` roster and that route's `.kxm/models/<route-id>.yaml`,
|
|
924
|
+
never from the agent file. The developer assignment runner reads
|
|
925
|
+
`.kxm/roles/*.yaml` and `.kxm/models/*.yaml` at `refs/remotes/origin/main`.
|
|
995
926
|
|
|
996
927
|
```yaml
|
|
997
928
|
schema: kxm.role.v2
|
|
@@ -1026,11 +957,10 @@ unknown keys are ignored).
|
|
|
1026
957
|
| `schema` | `kxm.routes.v2` | Required | Anything else fails with `invalid .kxm/routes.yaml` |
|
|
1027
958
|
| `admitted` | Array of route strings | Required | Runtime route check; `kxm routes list`, `kxm routes count`; `kxm models` |
|
|
1028
959
|
| `disabled` | Array of route strings | Optional, `[]` | Runtime: a disabled route is refused even if admitted |
|
|
1029
|
-
| `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/` |
|
|
1030
960
|
| `updatedAt` | ISO timestamp string | Optional | Rewritten by every CLI change |
|
|
1031
961
|
|
|
1032
|
-
A route string is
|
|
1033
|
-
`model
|
|
962
|
+
A route string is derived from the selected model file's `vendor` and
|
|
963
|
+
`model`, joined by a slash: `xai/grok-4.6`, `anthropic/fable`,
|
|
1034
964
|
`openrouter/qwen/qwen3-coder-plus`. When the file is missing, nothing is
|
|
1035
965
|
admitted and every live attempt is refused (`producer_route_unsupported`, or
|
|
1036
966
|
`producer_route_not_admitted` from the live producer). A leftover
|
|
@@ -1054,31 +984,29 @@ admitted:
|
|
|
1054
984
|
- xai/grok-4.6
|
|
1055
985
|
- openrouter/qwen/qwen3-coder-plus
|
|
1056
986
|
disabled: []
|
|
1057
|
-
roles:
|
|
1058
|
-
implementer:
|
|
1059
|
-
- xai/grok-4.6
|
|
1060
987
|
```
|
|
1061
988
|
|
|
1062
|
-
Validated with `kxm routes list --json` and `kxm routes count --json`.
|
|
989
|
+
Validated with `kxm routes list --json` and `kxm routes count --json`. `policy` has `admitted` and `disabled`. Membership comes from `.kxm/roles/*.yaml`, not from this file.
|
|
1063
990
|
|
|
1064
991
|
Commands: `kxm routes list|count|admit|disable` (`--dry-run` supported for
|
|
1065
992
|
changes), `kxm models` (interactive), the Runtime, and the live producer.
|
|
1066
993
|
Route changes are not part of `configRevision` and `kxm trust check` does not
|
|
1067
994
|
report them; review them in the pull request diff.
|
|
1068
995
|
|
|
1069
|
-
##
|
|
996
|
+
## Developer assignment policy
|
|
1070
997
|
|
|
1071
|
-
The developer roster for `scripts/assignment-run.mjs` (
|
|
1072
|
-
|
|
1073
|
-
source repository itself: the loader in `scripts/roster-policy.mjs` reads
|
|
1074
|
-
|
|
1075
|
-
refuses unless the worktree is clean,
|
|
1076
|
-
`origin/main`, and
|
|
1077
|
-
It has no dispatch authority in the project Runtime.
|
|
998
|
+
The developer roster for `scripts/assignment-run.mjs` (`kxm assign`; see
|
|
999
|
+
[Assignment runner](../contributing/assignment-runner.md)). It applies to the KXM
|
|
1000
|
+
source repository itself: the loader in `scripts/roster-policy.mjs` reads
|
|
1001
|
+
`.kxm/roles/*.yaml` and `.kxm/models/*.yaml` committed at `HEAD` of the
|
|
1002
|
+
repository that contains the script, and refuses unless the worktree is clean,
|
|
1003
|
+
`HEAD` is an ancestor of `origin/main`, and each working file is byte-identical
|
|
1004
|
+
to the committed one. It has no dispatch authority in the project Runtime.
|
|
1005
|
+
The assembled object has `routes`, `lineup`, `required_critics`, and `model_origins`.
|
|
1078
1006
|
|
|
1079
1007
|
| Field | Type and allowed values | Notes |
|
|
1080
1008
|
|---|---|---|
|
|
1081
|
-
| `
|
|
1009
|
+
| source files | `.kxm/roles/*.yaml` (`kxm.role.v2`), `.kxm/models/*.yaml` (`kxm.model.v2`) | The loader assembles the object below from these files |
|
|
1082
1010
|
| `routes.<id>` | Route ID matching `^[a-z0-9]+(?:-[a-z0-9]+)*$` | At least one route |
|
|
1083
1011
|
| `routes.<id>.harness` | `grok`, `agy`, `claude`, `codex`, or `pi` | Other harnesses are refused (`unsupported harness`) |
|
|
1084
1012
|
| `routes.<id>.model` | Token without whitespace | Native harnesses: a bare model ID. Pi: `openrouter/<vendor>/<model>`, `nous-portal/<vendor>/<model>`, or `antigravity/gemini-<id>` |
|
|
@@ -1098,8 +1026,7 @@ only`, `Pi critic/planner cannot edit`, `writer and critics must have
|
|
|
1098
1026
|
independent vendors`, and `retired .kxm/roster.json present`.
|
|
1099
1027
|
|
|
1100
1028
|
```yaml
|
|
1101
|
-
#
|
|
1102
|
-
schema: kxm.developer-roster.v1
|
|
1029
|
+
# Assembled by scripts/roster-policy.mjs from .kxm/roles/*.yaml and .kxm/models/*.yaml.
|
|
1103
1030
|
routes:
|
|
1104
1031
|
grok-native: # route id: lowercase words joined by "-"
|
|
1105
1032
|
harness: grok
|
|
@@ -1130,7 +1057,7 @@ routes:
|
|
|
1130
1057
|
permissions: [read-only]
|
|
1131
1058
|
status: admitted
|
|
1132
1059
|
lineup: # routes admitted for each role
|
|
1133
|
-
writer: [grok-native, qwen-openrouter-pi]
|
|
1060
|
+
writer: [grok-native, qwen-openrouter-pi, gemini-agy]
|
|
1134
1061
|
planner: [fable-claude]
|
|
1135
1062
|
reviewer-arch: [fable-claude]
|
|
1136
1063
|
reviewer-cli: [sol-codex]
|
|
@@ -1688,7 +1615,7 @@ Everything under `.kxm/` at the project root falls into one of three groups.
|
|
|
1688
1615
|
| Path | Group | Written by |
|
|
1689
1616
|
|---|---|---|
|
|
1690
1617
|
| `project.yaml`, `repo/`, `project/env.yaml`, `agents/`, `models/*.yaml` (except `inventory.yaml`), `workflows/`, `gates.yaml`, `template-provenance.yaml` | Tracked configuration (the bundle) | You and `kxm init` |
|
|
1691
|
-
| `roles/`, `routes.yaml`, `prices.yaml`, `modes.yaml`, `
|
|
1618
|
+
| `roles/`, `routes.yaml`, `prices.yaml`, `modes.yaml`, `the role files` | Tracked configuration outside the bundle | You and their commands |
|
|
1692
1619
|
| `config.yaml` | Tracked if the project wants shared preferences; otherwise ignore it | `kxm config set` |
|
|
1693
1620
|
| `memory/`, `skills/`, `candidates/`, `goals/` | Tracked durable records | Their commands |
|
|
1694
1621
|
| `models/inventory.yaml` | Generated; track it if you want a reviewed snapshot | `kxm models inventory-refresh` |
|
|
@@ -1883,7 +1810,6 @@ updatedAt: '2026-09-23T00:00:00.000Z'
|
|
|
1883
1810
|
admitted:
|
|
1884
1811
|
- xai/grok-4.6
|
|
1885
1812
|
disabled: []
|
|
1886
|
-
roles: {}
|
|
1887
1813
|
```
|
|
1888
1814
|
|
|
1889
1815
|
Why each piece is there:
|
|
@@ -1899,8 +1825,8 @@ Why each piece is there:
|
|
|
1899
1825
|
without a writable repository.
|
|
1900
1826
|
- The workflow omits `limits.maxAgentTimeMs`; with it, the Runtime refuses to
|
|
1901
1827
|
drive the run.
|
|
1902
|
-
-
|
|
1903
|
-
|
|
1828
|
+
- `kxm init` writes `.kxm/roles/writer.yaml`. The role file is the writer
|
|
1829
|
+
roster. An agent model is not checked against it.
|
|
1904
1830
|
|
|
1905
1831
|
Validate and run it:
|
|
1906
1832
|
|