@kontextmind/kxm 0.7.130 → 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.
Files changed (54) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.kxm/README.md +4 -1
  3. package/.kxm/agents/coordinator.yaml +1 -0
  4. package/.kxm/agents/critic-arch.yaml +1 -4
  5. package/.kxm/agents/critic-cli.yaml +1 -4
  6. package/.kxm/agents/implementer.yaml +1 -4
  7. package/.kxm/workflows/implement-only.yaml +1 -1
  8. package/.kxm/workflows/review-arch-only.yaml +1 -1
  9. package/.kxm/workflows/review-cli-only.yaml +1 -1
  10. package/CHANGELOG.md +22 -1
  11. package/docs/concepts/architecture.md +1 -1
  12. package/docs/contracts/routing.md +3 -3
  13. package/docs/contributing/assignment-runner.md +14 -15
  14. package/docs/contributing/development.md +19 -5
  15. package/docs/contributing/harness-routing-internals.md +8 -8
  16. package/docs/glossary.md +1 -1
  17. package/docs/guides/agent-skills.md +1 -1
  18. package/docs/operations/backup-and-restore.md +4 -4
  19. package/docs/reference/cli-reference.md +26 -8
  20. package/docs/reference/config-reference.md +76 -153
  21. package/docs/reference/harness-routing.md +29 -21
  22. package/docs/reference/workflow-catalog.md +4 -4
  23. package/docs/start/first-workflow.md +1 -1
  24. package/examples/project/.kxm/agents/coordinator.yaml +1 -2
  25. package/examples/project/.kxm/agents/critic-1.yaml +1 -3
  26. package/examples/project/.kxm/agents/critic-2.yaml +1 -2
  27. package/examples/project/.kxm/agents/critic-3.yaml +2 -3
  28. package/examples/project/.kxm/agents/implementer.yaml +1 -2
  29. package/examples/project/.kxm/agents/planner.yaml +1 -2
  30. package/examples/project/.kxm/agents/reproducer.yaml +1 -2
  31. package/examples/project/.kxm/agents/reviewer.yaml +1 -2
  32. package/examples/project/.kxm/workflows/fix.yaml +0 -12
  33. package/package.json +1 -1
  34. package/plugins/kxm/.claude-plugin/plugin.json +1 -1
  35. package/plugins/kxm/dist/cli.js +287 -249
  36. package/plugins/kxm/dist/mcp-server.js +1 -1
  37. package/plugins/kxm/dist/runtime-supervisor.js +222 -242
  38. package/plugins/kxm/dist/runtime.js +224 -244
  39. package/plugins/kxm/package.json +1 -1
  40. package/plugins/kxm/skills/kxm/SKILL.md +1 -1
  41. package/plugins/kxm/skills/kxm-definitions/SKILL.md +8 -0
  42. package/plugins/kxm/src/cli/project.ts +4 -4
  43. package/plugins/kxm/src/engine.ts +168 -163
  44. package/plugins/kxm/src/init-guide-setup.ts +75 -15
  45. package/plugins/kxm/src/mcp-server.ts +1 -1
  46. package/plugins/kxm/src/oneshot-producer.ts +3 -15
  47. package/plugins/kxm/src/project-config.ts +83 -70
  48. package/plugins/kxm/src/routes.ts +26 -18
  49. package/plugins/kxm/src/runtime-supervisor.ts +0 -18
  50. package/plugins/kxm/src/suggest.ts +2 -2
  51. package/plugins/kxm/src/template.ts +2 -14
  52. package/schemas/agent.schema.json +8 -0
  53. package/scripts/roster-policy.d.mts +2 -1
  54. package/scripts/roster-policy.mjs +119 -22
@@ -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 harness, model, and permission ceilings | You; `kxm init` creates two | Yes |
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
- │ ├─ harness ──> pi | claude | codex | grok | agy | kimi | deepseek
61
- │ ├─ model ────> {provider, model} | {profile} | {tag}
62
- │ │ └─> .kxm/models/<id>.yaml
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 model "provider/model" ──> .kxm/routes.yaml: admitted and not disabled
68
- └─> .kxm/roles/<role>.yaml roster, if that file exists
69
- (role = agent id; "writer" for agent "implementer")
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, agent models, `routes.yaml`, `roles/` | `kxm runs drive` and live drives, per step |
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`, `roster.yaml`, `prices.yaml`, `inventory.yaml`,
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 for agents without `harness`; fallback harness for live dispatch |
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`) |
@@ -322,15 +323,21 @@ One file per agent; the filename is the agent ID that workflow steps
322
323
  reference. Schema: `schemas/agent.schema.json`; semantic checks in
323
324
  `validateBundle` in `plugins/kxm/src/project-config.ts`.
324
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
+
325
331
  | Field | Type and allowed values | Required, default | What reads it |
326
332
  |---|---|---|---|
327
333
  | `schema` | `kxm.agent.v1` | Required | Loader |
328
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 |
329
338
  | `instructions` | String, at most 16,000 characters | Optional | Not read by any code path yet. Step `instructions` are what reach the prompt. |
330
- | `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 |
331
- | `model` | One selector: `{provider, model}`, `{profile}`, or `{tag, capabilities}` | Optional | See [Model selectors](#model-selectors) |
332
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 |
333
- | `tools.preset` | `coordinator`, `read-only`, `workspace-writer`, or `tests-writer` | Optional | Loader (`tool_preset_unknown`); pinned in the tool-policy revision |
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). |
334
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 |
335
342
  | `defaultRepositoryAccess` | `none`, `read`, or `write` | Optional; the ceiling is `none` when absent | Loader: access ceiling for repositories not listed in `repositories` |
336
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`) |
@@ -343,80 +350,24 @@ reference. Schema: `schemas/agent.schema.json`; semantic checks in
343
350
  | `session.maxIdleMs` | Integer, 0 to 31,536,000,000 | Optional | Not read by any code path yet |
344
351
 
345
352
  Tool presets are names checked against a registered list. The live one-shot
346
- producer launches each harness with a fixed argument set and does not
347
- translate `tools` into harness flags. A read-only step uses the read-only set
348
- (`READ_ONLY_ONESHOT_ARGS` in `plugins/kxm/src/harness.ts`). A step with `write`
349
- access uses the audited writer set (`WRITER_ONESHOT_ARGS`), which exists only
350
- for `pi` (`-a` with extensions, skills, prompt templates and sessions off) and
351
- `grok` (`--always-approve` with subagents and web search off). Both approve
352
- every tool call, shell commands included, and neither confines the process to
353
- the checkout. A live write step on any other harness is handed off; see
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
354
362
  [Steps the Runtime does not execute yet](#steps-the-runtime-does-not-execute-yet).
355
363
 
356
- ### Model selectors
357
-
358
- A selector has exactly one of three shapes (`common.schema.json#/$defs/modelSelector`):
359
-
360
- | Shape | Fields | Resolves to |
361
- |---|---|---|
362
- | 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`. |
363
- | Profile | `profile` (identifier) | `.kxm/models/<profile>.yaml` (`model_profile_unknown` if missing) |
364
- | Tag | `tag` (identifier), optional `capabilities` (identifiers) | Every profile carrying the tag and all listed capabilities (`model_tag_unresolved` if none) |
365
-
366
- For live dispatch, only the direct shape works. The Runtime reads the agent's
367
- `model.provider` and `model.model` and joins them into the route string; a
368
- profile or tag selector validates at load time but live dispatch refuses the
369
- step with `producer_route_unsupported: invalid model declaration`. An agent
370
- with no model is refused too, except that an agent named `implementer`
371
- without a model falls back to `xai/grok-4.6`.
372
-
373
- ### Harness and model pairing
374
-
375
- The loader checks that the agent's harness can host its model, using
376
- `validateHarnessModelPair` in `plugins/kxm/src/harness.ts`. It applies this
377
- check only to models reached through a profile or tag selector. A direct
378
- `{provider, model}` selector is not checked at load time; the live producer
379
- checks it when it probes the harness before dispatch.
380
-
381
- | Harness | Accepts |
382
- |---|---|
383
- | `claude` | Provider `anthropic`; rejects model IDs starting with `gpt-`, `o1-`, `o3-`, `grok-`, `gemini-`, `kimi-`, `moonshot-`, `deepseek-`, or `qwen-` |
384
- | `codex` | Provider `openai`; rejects `claude-`, `fable-`, `grok-`, `gemini-`, `kimi-`, `moonshot-`, `deepseek-`, and `qwen-` models |
385
- | `grok` | Provider `xai` and `grok-` models |
386
- | `agy` | Provider `google` and `gemini-` models |
387
- | `kimi` | Provider `moonshot` and `kimi`, `moonshot`, or `kimi-for-coding` models |
388
- | `deepseek` | Provider `deepseek` and `deepseek-` models |
389
- | `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) |
390
-
391
- A mismatch is reported as `harness_unhosted_model`. Which route to choose for a
392
- model that more than one harness can reach is covered in
393
- [Harness routing](harness-routing.md).
394
-
395
- ### Live dispatch requirements
396
-
397
- Before a live attempt, the Runtime (`resolveProducerRoute` in
398
- `plugins/kxm/src/engine.ts`) requires all of the following. A failure hands the
399
- run off with `step_unsupported` and a `producer_route_unsupported` detail.
400
-
401
- 1. The agent declares a direct `{provider, model}` selector (see above).
402
- 2. `provider/model` is listed in `.kxm/routes.yaml` `admitted` and not in
403
- `disabled`.
404
- 3. If `.kxm/roles/<role>.yaml` exists, its roster contains exactly
405
- `provider/model`. The role is the agent ID, except that agent
406
- `implementer` maps to role `writer`.
407
-
408
- Example (validated with `kxm init --json`):
364
+ Example (the shape `kxm init` writes for `implementer`):
409
365
 
410
366
  ```yaml
411
- # .kxm/agents/implementer.yaml — the filename is the agent id.
367
+ # .kxm/agents/implementer.yaml. The filename is the agent id.
412
368
  schema: kxm.agent.v1
413
369
  purpose: Implement the approved change within the declared repository scope.
414
- instructions: Keep changes inside the files named by the approved plan.
415
- harness: grok # pi | claude | codex | grok | agy | kimi | deepseek
416
- model: # direct selector: provider + model
417
- provider: xai
418
- model: grok-4.6
419
- executor: local # local | ssh | exe-dev
370
+ role: writer # .kxm/roles/writer.yaml -> .kxm/models/<route>.yaml
420
371
  tools:
421
372
  preset: workspace-writer # coordinator | read-only | workspace-writer | tests-writer
422
373
  allow: [read, edit, write, bash]
@@ -424,47 +375,26 @@ tools:
424
375
  defaultRepositoryAccess: none # ceiling for repositories not listed below
425
376
  repositories:
426
377
  control: write
427
- api: write
428
378
  secrets:
429
379
  - ref: npm-token # secret reference name
430
380
  as: NPM_TOKEN # environment variable name inside the attempt
431
381
  required: false
432
382
  network: provider-only # none | provider-only | restricted | host
433
383
  resultSchema: kxm.assignment-result.v1
434
- session:
435
- reuse: compatible-run-scope
436
- maxIdleMs: 1800000
437
384
  ```
438
385
 
439
- A critic that uses a profile selector:
440
-
441
- ```yaml
442
- schema: kxm.agent.v1
443
- purpose: Architecture critic for the approved change.
444
- harness: claude
445
- model:
446
- profile: critic-claude # profile selector: .kxm/models/critic-claude.yaml
447
- tools:
448
- preset: read-only
449
- defaultRepositoryAccess: read
450
- network: provider-only
451
- resultSchema: kxm.assignment-result.v1
452
- ```
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.
453
393
 
454
- Error codes: `executor_unknown`, `harness_unknown`, `tool_preset_unknown`,
455
- `tool_policy_contradiction`, `repository_unknown`, `model_profile_unknown`,
456
- `model_tag_unresolved`, `harness_unhosted_model`,
457
- `pi_native_impersonation_blocked`, the path codes under
458
- [Rules shared by the project bundle](#rules-shared-by-the-project-bundle), and
459
- `role_roster_conflicts_with_agent` (see [Roles](#kxmrolesroleyaml-kxmrolev2)).
460
-
461
- Commands: `kxm init` creates `coordinator` (`claude`, `anthropic/fable`) and
462
- `implementer` (`grok`, `xai/grok-4.6`) and admits both selectors in
463
- `.kxm/routes.yaml`; an interactive `kxm init` can add workflow-guide agents for
464
- reviewed harness/model pairs whose harness is authenticated, and admits their
465
- selectors too, but skips Google guide candidates because the Runtime cannot
466
- reach the `antigravity` Pi provider yet; `kxm run` and the Runtime read them;
467
- `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).
468
398
 
469
399
  ## `.kxm/models/<id>.yaml` (`kxm.model.v2`)
470
400
 
@@ -503,11 +433,11 @@ status: admitted
503
433
  permissions:
504
434
  - edit
505
435
  origin:
506
- source: .kxm/roster.yaml
507
- sha256: b2bd628604e8fec5afdff2a1f2c104ed14ff785686bb1f38272bc972a310c806
436
+ source: docs/reference/harness-routing.md
437
+ sha256: 321c821ed6dbce7b2e98309fdc29387671577049619b6979c685a7ba60c63337
508
438
  ```
509
439
 
510
- 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 still reads `.kxm/roster.yaml` until P2.
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`.
511
441
 
512
442
  ## `.kxm/workflows/<id>.yaml` (`kxm.workflow.v1`)
513
443
 
@@ -695,9 +625,8 @@ these, the run is handed off (`step_unsupported`, `gate_unsupported`, or
695
625
  - A live (non-simulated) step with `write` access to any repository when its
696
626
  agent's harness has no audited writer profile (only `pi` and `grok` have
697
627
  one), when `assignments.maximum` is above 1, when the project's
698
- `limits.maxConcurrentRuns` is above 1, or when `.kxm/roster.yaml` exists and
699
- is not a `kxm.developer-roster.v1` whose writer lineup admits that harness
700
- 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
701
630
  change only to one writer at a time.
702
631
  - Gate steps with `assignments.allowedAgents`, any assignment count or
703
632
  `maxAttemptsPerAssignment` other than 1, `distinctBy`,
@@ -965,12 +894,10 @@ not this registry.
965
894
  One role. The filename is the role id. `kxm config` validation checks the file
966
895
  against `schemas/role.schema.json`.
967
896
 
968
- `listRoleBindings` reads `roster[].route`. Dispatch treats `implementer` as
969
- `writer` and requires the agent selector to be one of the selectors named by
970
- those route files (`model`, `vendor/model`, or `harness/model`). The writer
971
- cross-check (`role_roster_conflicts_with_agent`) does the same comparison
972
- against the `implementer` agent's model, or the `writer` agent when there is
973
- 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
974
901
  `schema: kxm.role.v2` is skipped by `kxm role`. A local file overrides a
975
902
  global one with the same id.
976
903
 
@@ -992,9 +919,10 @@ global one with the same id.
992
919
  | `policy.vendorIndependenceRequired`, `policy.maxTransitions`, `policy.requiresGateVerification` | Boolean, or a positive integer for `maxTransitions` | Optional | Recorded on the role |
993
920
 
994
921
  Roster order is preference. `kxm role list` shows the first route as the
995
- primary. The Runtime checks membership. The model that runs still comes from
996
- the agent file. The developer assignment runner still reads `.kxm/roster.yaml`
997
- until P2.
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`.
998
926
 
999
927
  ```yaml
1000
928
  schema: kxm.role.v2
@@ -1029,11 +957,10 @@ unknown keys are ignored).
1029
957
  | `schema` | `kxm.routes.v2` | Required | Anything else fails with `invalid .kxm/routes.yaml` |
1030
958
  | `admitted` | Array of route strings | Required | Runtime route check; `kxm routes list`, `kxm routes count`; `kxm models` |
1031
959
  | `disabled` | Array of route strings | Optional, `[]` | Runtime: a disabled route is refused even if admitted |
1032
- | `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/` |
1033
960
  | `updatedAt` | ISO timestamp string | Optional | Rewritten by every CLI change |
1034
961
 
1035
- A route string is exactly the agent's `model.provider`, a slash, and
1036
- `model.model`: `xai/grok-4.6`, `anthropic/fable`,
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`,
1037
964
  `openrouter/qwen/qwen3-coder-plus`. When the file is missing, nothing is
1038
965
  admitted and every live attempt is refused (`producer_route_unsupported`, or
1039
966
  `producer_route_not_admitted` from the live producer). A leftover
@@ -1057,31 +984,29 @@ admitted:
1057
984
  - xai/grok-4.6
1058
985
  - openrouter/qwen/qwen3-coder-plus
1059
986
  disabled: []
1060
- roles:
1061
- implementer:
1062
- - xai/grok-4.6
1063
987
  ```
1064
988
 
1065
- 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.
1066
990
 
1067
991
  Commands: `kxm routes list|count|admit|disable` (`--dry-run` supported for
1068
992
  changes), `kxm models` (interactive), the Runtime, and the live producer.
1069
993
  Route changes are not part of `configRevision` and `kxm trust check` does not
1070
994
  report them; review them in the pull request diff.
1071
995
 
1072
- ## `.kxm/roster.yaml` (`kxm.developer-roster.v1`)
996
+ ## Developer assignment policy
1073
997
 
1074
- The developer roster for `scripts/assignment-run.mjs` (the `just` assignment
1075
- recipes; see [Assignment runner](../contributing/assignment-runner.md)). It applies to the KXM
1076
- source repository itself: the loader in `scripts/roster-policy.mjs` reads the
1077
- copy committed at `HEAD` of the repository that contains the script, and
1078
- refuses unless the worktree is clean, `HEAD` is an ancestor of
1079
- `origin/main`, and the working file is byte-identical to the committed one.
1080
- 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`.
1081
1006
 
1082
1007
  | Field | Type and allowed values | Notes |
1083
1008
  |---|---|---|
1084
- | `schema` | `kxm.developer-roster.v1` | The five top-level keys are all required and no others are allowed |
1009
+ | source files | `.kxm/roles/*.yaml` (`kxm.role.v2`), `.kxm/models/*.yaml` (`kxm.model.v2`) | The loader assembles the object below from these files |
1085
1010
  | `routes.<id>` | Route ID matching `^[a-z0-9]+(?:-[a-z0-9]+)*$` | At least one route |
1086
1011
  | `routes.<id>.harness` | `grok`, `agy`, `claude`, `codex`, or `pi` | Other harnesses are refused (`unsupported harness`) |
1087
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>` |
@@ -1101,8 +1026,7 @@ only`, `Pi critic/planner cannot edit`, `writer and critics must have
1101
1026
  independent vendors`, and `retired .kxm/roster.json present`.
1102
1027
 
1103
1028
  ```yaml
1104
- # .kxm/roster.yaml — developer roster policy for scripts/assignment-run.mjs.
1105
- schema: kxm.developer-roster.v1
1029
+ # Assembled by scripts/roster-policy.mjs from .kxm/roles/*.yaml and .kxm/models/*.yaml.
1106
1030
  routes:
1107
1031
  grok-native: # route id: lowercase words joined by "-"
1108
1032
  harness: grok
@@ -1133,7 +1057,7 @@ routes:
1133
1057
  permissions: [read-only]
1134
1058
  status: admitted
1135
1059
  lineup: # routes admitted for each role
1136
- writer: [grok-native, qwen-openrouter-pi]
1060
+ writer: [grok-native, qwen-openrouter-pi, gemini-agy]
1137
1061
  planner: [fable-claude]
1138
1062
  reviewer-arch: [fable-claude]
1139
1063
  reviewer-cli: [sol-codex]
@@ -1691,7 +1615,7 @@ Everything under `.kxm/` at the project root falls into one of three groups.
1691
1615
  | Path | Group | Written by |
1692
1616
  |---|---|---|
1693
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` |
1694
- | `roles/`, `routes.yaml`, `prices.yaml`, `modes.yaml`, `roster.yaml` | Tracked configuration outside the bundle | You and their commands |
1618
+ | `roles/`, `routes.yaml`, `prices.yaml`, `modes.yaml`, `the role files` | Tracked configuration outside the bundle | You and their commands |
1695
1619
  | `config.yaml` | Tracked if the project wants shared preferences; otherwise ignore it | `kxm config set` |
1696
1620
  | `memory/`, `skills/`, `candidates/`, `goals/` | Tracked durable records | Their commands |
1697
1621
  | `models/inventory.yaml` | Generated; track it if you want a reviewed snapshot | `kxm models inventory-refresh` |
@@ -1886,7 +1810,6 @@ updatedAt: '2026-09-23T00:00:00.000Z'
1886
1810
  admitted:
1887
1811
  - xai/grok-4.6
1888
1812
  disabled: []
1889
- roles: {}
1890
1813
  ```
1891
1814
 
1892
1815
  Why each piece is there:
@@ -1902,8 +1825,8 @@ Why each piece is there:
1902
1825
  without a writable repository.
1903
1826
  - The workflow omits `limits.maxAgentTimeMs`; with it, the Runtime refuses to
1904
1827
  drive the run.
1905
- - There is no `.kxm/roles/writer.yaml`. If you add one, it must list
1906
- `xai/grok-4.6`, or the loader reports `role_roster_conflicts_with_agent`.
1828
+ - `kxm init` writes `.kxm/roles/writer.yaml`. The role file is the writer
1829
+ roster. An agent model is not checked against it.
1907
1830
 
1908
1831
  Validate and run it:
1909
1832
 
@@ -99,35 +99,43 @@ pi auth check --model openrouter/qwen/qwen3-coder-plus --json --no-refresh
99
99
 
100
100
  ### How KXM builds a route
101
101
 
102
- - **Selector.** The selector is `<model.provider>/<model.model>`, taken from the agent YAML. The provider must not contain `/`. The model id may, for example `qwen/qwen3-coder-plus` under `openrouter`.
103
- - **Harness.** The harness is the agent's `harness:`, or the project's `defaultHarness` (Pi) when the agent omits it. The selector string does not choose the harness, and neither does a roster entry.
104
- - **Admission.** The selector must be admitted, and it must be in the role roster when that role file exists. Agent id `implementer` maps to role `writer`.
102
+ - **Selector.** The selector is `<vendor>/<model>` from the selected `.kxm/models/<route>.yaml`. The agent names a `role`, `.kxm/roles/<role>.yaml` lists route ids, and the chosen roster entry names that model file. The model id may contain `/`, for example `openrouter/qwen/qwen3-coder-plus`.
103
+ - **Harness.** The harness is the `harness` field on that model file. An agent file does not select it.
104
+ - **Admission.** The selector must be admitted. The engine uses the first roster entry whose model file is readable and whose route is admitted.
105
105
  - **Dispatch probe.** Before spawning anything, the producer probes the exact harness, provider and model triple. It refuses unhosted pairs and the Pi brake.
106
106
  - **Effort.** The Runtime sets the thinking effort per attempt: the first attempt of a step runs at `low`, and any later attempt of the same step at `medium`. The live producer passes it as `--effort` to `claude`, as `model_reasoning_effort` to `codex` and as `--reasoning-effort` to `grok`. `agy`, `kimi` and `pi` get no effort flag. A roster entry's `effort` is display-only.
107
107
 
108
108
  ### Agent YAML
109
109
 
110
- This is the native route, from `.kxm/agents/implementer.yaml`:
110
+ An agent names a role and nothing else about the route:
111
+
112
+ ```yaml
113
+ role: writer
114
+ ```
115
+
116
+ `harness` and `model` on an agent file are refused at load (`retired_agent_routing_fields`). A step `model` is refused at load and again at dispatch (`producer_route_unsupported`).
117
+
118
+ ### Model file
119
+
120
+ This is the native route, from `.kxm/models/grok-native.yaml`:
111
121
 
112
122
  ```yaml
113
123
  harness: grok
114
- model:
115
- provider: xai
116
- model: grok-4.6
124
+ model: grok-4.7
125
+ vendor: xai
117
126
  ```
118
127
 
119
- The selector is `xai/grok-4.6` and the harness is `grok`. The live one-shot producer spawns `grok --model grok-4.6 … --output-format json --single <prompt>`.
128
+ The selector is `xai/grok-4.7` and the harness is `grok`. The live one-shot producer spawns `grok --model grok-4.7 … --output-format json --single <prompt>`.
120
129
 
121
- This is the same model through Pi and OpenRouter:
130
+ This is the same vendor through Pi and OpenRouter, which the brake refuses:
122
131
 
123
132
  ```yaml
124
- # harness omitted: Pi
125
- model:
126
- provider: openrouter
127
- model: x-ai/grok-4.6
133
+ harness: pi
134
+ model: openrouter/x-ai/grok-4.6
135
+ vendor: xai
128
136
  ```
129
137
 
130
- The selector is `openrouter/x-ai/grok-4.6` and the harness is `pi`. The Pi brake refuses it before Pi starts, because the vendor segment `x-ai` is xAI, which has a native harness. A vendor with no native harness runs in the same shape: with `model: qwen/qwen3-coder-plus`, Pi is spawned with `--model openrouter/qwen/qwen3-coder-plus`, its read-only flags (section 3) and `-p --mode json`. Write `model.model` exactly as the provider names it. For OpenRouter that is the vendor slug, so `x-ai`, not `xai`.
138
+ The selector is `openrouter/x-ai/grok-4.6` and the harness is `pi`. The Pi brake refuses it before Pi starts, because the vendor segment `x-ai` is xAI, which has a native harness. A vendor with no native harness runs in the same shape: with `model: openrouter/qwen/qwen3-coder-plus`, Pi is spawned with `--model openrouter/qwen/qwen3-coder-plus`, its read-only flags (section 3) and `-p --mode json`. Write `model` exactly as the provider names it. For OpenRouter that is the vendor slug, so `x-ai`, not `xai`.
131
139
 
132
140
  The harness and the selector have to agree. Pi refuses `provider: xai` and `openrouter/x-ai/…`. `grok` refuses `provider: openrouter`. [What the brake refuses](#what-the-brake-refuses) has the exact messages.
133
141
 
@@ -152,9 +160,9 @@ roster:
152
160
 
153
161
  `grok-native` resolves to `.kxm/models/grok-native.yaml`: harness `grok`, model `grok-4.7`, vendor `xai`, status `admitted`, permission `edit`. `qwen-openrouter-pi` is harness `pi`, model `openrouter/qwen/qwen3-coder-plus`, vendor `alibaba`. `gemini-agy` is harness `agy`, model `gemini-3.8-flash-high`, vendor `google`. `kxm role list` prints the first route id as the primary, for example `(grok-native)`.
154
162
 
155
- The model that runs a step still comes from the agent file. The harness is the agent's `harness:`, or Pi when the agent omits it. A route file records which harness can host that model; it does not replace the agent. If the implementer agent declares `harness: grok`, only the Grok selector can run under it. A Pi selector under that agent fails closed with `grok_not_authenticated: grok harness not detected (harness_unhosted_model)`. To run a Pi selector, create a separate agent with `harness:` omitted. The engine does not walk the roster to fail over on its own.
163
+ Dispatch resolves a step from the agent `role`, then `.kxm/roles/<role>.yaml`, then the selected `.kxm/models/<route>.yaml`. That model file carries `harness`, `model`, `vendor`, `status`, and `permissions`. The engine walks the roster in order and uses the first admitted route whose model file is readable. A missing or unreadable model file is a refusal (`roster_model_unreadable` at load, `producer_route_unsupported` at dispatch), not a skip to the next entry. A route file that names a harness the model cannot run on still fails closed with `harness_unhosted_model`.
156
164
 
157
- Dispatch still reads `.kxm/roster.yaml` until P2. Role files are what `kxm role` and the Runtime membership check use.
165
+ Role files are what `kxm role` and the Runtime membership check use.
158
166
 
159
167
  ### Route ids in `.kxm/routes.yaml`
160
168
 
@@ -308,7 +316,7 @@ kxm routing report --file ./run-events.jsonl --equivalent-list-cost
308
316
 
309
317
  ## 3. Examples: the same model, two routes
310
318
 
311
- Each example shows the agent YAML for the native route and for the same model through Pi, and which one the rules pick. For a native vendor, the Pi brake refuses the Pi column; it is shown so that you recognize the id. Whether a route is admitted is in your `.kxm/routes.yaml`. List prices and context sizes are in `.kxm/models/inventory.yaml` after `kxm models inventory-refresh`, and `pi --list-models` shows context, max output, thinking and image support per model. A provider missing from `pi --list-models` usually has no credentials, which is itself a readiness hint.
319
+ Each example shows the model file for the native route and for the same model through Pi, and which one the rules pick. For a native vendor, the Pi brake refuses the Pi column; it is shown so that you recognize the id. Whether a route is admitted is in your `.kxm/routes.yaml`. List prices and context sizes are in `.kxm/models/inventory.yaml` after `kxm models inventory-refresh`, and `pi --list-models` shows context, max output, thinking and image support per model. A provider missing from `pi --list-models` usually has no credentials, which is itself a readiness hint.
312
320
 
313
321
  ### How the live producer runs each harness
314
322
 
@@ -330,7 +338,7 @@ The Runtime does not run a step live when it has `write` access to a repository;
330
338
 
331
339
  | | Native `grok` | Pi + OpenRouter |
332
340
  |---|---|---|
333
- | Agent YAML | `harness: grok`, `provider: xai`, `model: grok-4.6` | `harness:` omitted, `provider: openrouter`, `model: x-ai/grok-4.6` |
341
+ | Model file | `harness: grok`, `model: grok-4.6`, `vendor: xai` | `harness: pi`, `model: openrouter/x-ai/grok-4.6`, `vendor: xai` |
334
342
  | Selector | `xai/grok-4.6` | `openrouter/x-ai/grok-4.6` |
335
343
  | Billing | grok.com subscription (OAuth) | OpenRouter credit |
336
344
  | Recorded `costBasis` | `unknown` | None: the brake refuses it before dispatch |
@@ -350,7 +358,7 @@ pi auth check --provider xai --json --no-refresh
350
358
 
351
359
  | | Native `codex` | Pi + OpenRouter |
352
360
  |---|---|---|
353
- | Agent YAML | `harness: codex`, `provider: openai`, `model: gpt-5.6-sol` | `harness:` omitted, `provider: openrouter`, `model: openai/gpt-5.6-sol` |
361
+ | Model file | `harness: codex`, `model: gpt-5.6-sol`, `vendor: openai` | `harness: pi`, `model: openrouter/openai/gpt-5.6-sol`, `vendor: openai` |
354
362
  | Selector | `openai/gpt-5.6-sol` | `openrouter/openai/gpt-5.6-sol` |
355
363
  | Readiness | Needs `codex` auth `yes` with `authMethod: ChatGPT` | Never reached: the brake refuses it first |
356
364
  | Billing | ChatGPT subscription | OpenRouter credit |
@@ -373,7 +381,7 @@ A larger context window on the OpenRouter route does not make OpenRouter an allo
373
381
 
374
382
  | | Native `claude` | Pi + OpenRouter |
375
383
  |---|---|---|
376
- | Agent YAML | `harness: claude`, `provider: anthropic`, `model: fable` | `harness:` omitted, `provider: openrouter`, `model: anthropic/claude-fable-5.1` |
384
+ | Model file | `harness: claude`, `model: fable`, `vendor: anthropic` | `harness: pi`, `model: openrouter/anthropic/claude-fable-5.1`, `vendor: anthropic` |
377
385
  | Selector | `anthropic/fable` | `openrouter/anthropic/claude-fable-5.1` |
378
386
  | Billing | claude.ai subscription | OpenRouter credit |
379
387
  | Recorded `costBasis` | `unmetered`, `priceRef: subscription:claude`, plus a list estimate when `prices.yaml` has an `anthropic` row dated today | None: refused before dispatch |
@@ -385,7 +393,7 @@ A larger context window on the OpenRouter route does not make OpenRouter an allo
385
393
 
386
394
  | | Native `agy` | `antigravity` Pi provider | Pi + OpenRouter |
387
395
  |---|---|---|---|
388
- | Agent YAML | `harness: agy`, `provider: google`, `model: gemini-3.8-flash-high` | `harness:` omitted, `provider: antigravity`, `model: gemini-3.8-flash` | `harness:` omitted, `provider: openrouter`, `model: google/gemini-3.8-flash` |
396
+ | Model file | `harness: agy`, `model: gemini-3.8-flash-high`, `vendor: google` | `harness: pi`, `model: antigravity/gemini-3.8-flash`, `vendor: google` | `harness: pi`, `model: openrouter/google/gemini-3.8-flash`, `vendor: google` |
389
397
  | Selector | `google/gemini-3.8-flash-high` | `antigravity/gemini-3.8-flash` | `openrouter/google/gemini-3.8-flash` |
390
398
  | Readiness | Needs `agy` auth `yes` (`antigravity-oauth`) | Registered only by the KXM Pi extension. `pi auth check` never loads extensions, so `pi auth check --provider antigravity` returns `provider_not_found`. | Never reached: the brake refuses it (vendor segment `google`) |
391
399
  | Billing | Google subscription | Google subscription | OpenRouter credit |
@@ -1094,11 +1094,11 @@ This cross-reference points each software and security workflow at the KXM pages
1094
1094
 
1095
1095
  These three files live in this repository's `.kxm/workflows`. `kxm init` does not write them.
1096
1096
 
1097
- | Workflow | Replaces |
1097
+ | Workflow | Runs through |
1098
1098
  |---|---|
1099
- | `implement-only` | `just impl`. The recipe is retired once this lands. |
1100
- | `review-arch-only` | `just review-arch`. The recipe is retired once this lands. |
1101
- | `review-cli-only` | `just review-cli`. The recipe is retired once this lands. |
1099
+ | `implement-only` | `kxm lane run`. Replaces a retired transport recipe. |
1100
+ | `review-arch-only` | `kxm lane run`. Replaces a retired transport recipe. |
1101
+ | `review-cli-only` | `kxm lane run`. Replaces a retired transport recipe. |
1102
1102
 
1103
1103
  ## Related
1104
1104
 
@@ -254,7 +254,7 @@ The file is a `kxm.workflow.v1` definition. `coordinator` names the agent that o
254
254
  | Cost | None | Model usage on your accounts |
255
255
 
256
256
  > [!WARNING]
257
- > Without `--simulated`, `kxm runs drive` calls live harnesses. An agent whose model is not an admitted route fails with `producer_route_not_admitted`. Read [Harness routing](../reference/harness-routing.md) before your first live drive. A live step with `write` access runs only on a harness with an audited writer profile (`pi` or `grok`), as a single assignment, in a project whose `limits.maxConcurrentRuns` is 1, and, when `.kxm/roster.yaml` exists, only on a route in its writer lineup; any other live write step is handed off. A live write step settles `passed` only when the checkout changed, and a read-only step that changes the checkout settles `failed`. Gate steps are exempt. The read-only `spec-and-plan` template needs none of this.
257
+ > Without `--simulated`, `kxm runs drive` calls live harnesses. An agent whose model is not an admitted route fails with `producer_route_not_admitted`. Read [Harness routing](../reference/harness-routing.md) before your first live drive. A live step with `write` access runs only on a harness with an audited writer profile (`pi` or `grok`), as a single assignment, in a project whose `limits.maxConcurrentRuns` is 1, and only on a route in the writer roster under `.kxm/roles/writer.yaml`; any other live write step is handed off. A live write step settles `passed` only when the checkout changed, and a read-only step that changes the checkout settles `failed`. Gate steps are exempt. The read-only `spec-and-plan` template needs none of this.
258
258
 
259
259
  ### Why start with `first` and not `default`
260
260
 
@@ -1,7 +1,6 @@
1
1
  schema: kxm.agent.v1
2
2
  purpose: Coordinate the pinned workflow and emit only schema-validated commands.
3
- model:
4
- profile: primary
3
+ role: planner
5
4
  tools:
6
5
  preset: coordinator
7
6
  defaultRepositoryAccess: read
@@ -1,8 +1,6 @@
1
1
  schema: kxm.agent.v1
2
2
  purpose: First fixed-identity critic for migrated strict producer policies.
3
- harness: claude
4
- model:
5
- profile: critic-claude
3
+ role: reviewer-arch
6
4
  tools:
7
5
  preset: read-only
8
6
  defaultRepositoryAccess: read
@@ -1,7 +1,6 @@
1
1
  schema: kxm.agent.v1
2
2
  purpose: Second fixed-identity critic for migrated strict producer policies.
3
- model:
4
- profile: critic-grok
3
+ role: reviewer-cli
5
4
  tools:
6
5
  preset: read-only
7
6
  defaultRepositoryAccess: read
@@ -1,7 +1,6 @@
1
1
  schema: kxm.agent.v1
2
- purpose: Third provider-distinct critic used by the KXM MOA target.
3
- model:
4
- profile: critic-gemini
2
+ purpose: Third architecture critic, bound to reviewer-arch like critic-1.
3
+ role: reviewer-arch
5
4
  tools:
6
5
  preset: read-only
7
6
  defaultRepositoryAccess: read
@@ -1,7 +1,6 @@
1
1
  schema: kxm.agent.v1
2
2
  purpose: Implement the approved plan in the assignment-owned repository worktree.
3
- model:
4
- tag: implementation
3
+ role: writer
5
4
  tools:
6
5
  preset: workspace-writer
7
6
  defaultRepositoryAccess: none