@kontextmind/kxm 0.7.123 → 0.7.124

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.
@@ -11,7 +11,7 @@
11
11
  "name": "kxm",
12
12
  "source": "./plugins/kxm",
13
13
  "description": "Durable workflows, peer agents, and kxm tui",
14
- "version": "0.7.123",
14
+ "version": "0.7.124",
15
15
  "category": "development",
16
16
  "tags": ["kxm", "multi-agent", "workflows", "mcp"]
17
17
  }
@@ -0,0 +1,20 @@
1
+ schema: kxm.workflow.v1
2
+ description: One implementer step with a drive receipt. Replaces just impl.
3
+ coordinator: coordinator
4
+ limits:
5
+ maxTransitions: 2
6
+ steps:
7
+ - id: implement
8
+ kind: agent
9
+ agent: implementer
10
+ repositories:
11
+ control: write
12
+ maxAttempts: 1
13
+ timeoutMs: 3600000
14
+ on:
15
+ passed:
16
+ target: $terminal
17
+ terminalStatus: completed
18
+ failed:
19
+ target: $terminal
20
+ terminalStatus: failed
@@ -0,0 +1,20 @@
1
+ schema: kxm.workflow.v1
2
+ description: One read-only architecture critic step. Replaces just review-arch.
3
+ coordinator: coordinator
4
+ limits:
5
+ maxTransitions: 2
6
+ steps:
7
+ - id: critic-arch
8
+ kind: agent
9
+ agent: critic-arch
10
+ repositories:
11
+ control: read
12
+ maxAttempts: 1
13
+ timeoutMs: 1800000
14
+ on:
15
+ passed:
16
+ target: $terminal
17
+ terminalStatus: completed
18
+ failed:
19
+ target: $terminal
20
+ terminalStatus: failed
@@ -0,0 +1,20 @@
1
+ schema: kxm.workflow.v1
2
+ description: One read-only CLI critic step. Replaces just review-cli.
3
+ coordinator: coordinator
4
+ limits:
5
+ maxTransitions: 2
6
+ steps:
7
+ - id: critic-cli
8
+ kind: agent
9
+ agent: critic-cli
10
+ repositories:
11
+ control: read
12
+ maxAttempts: 1
13
+ timeoutMs: 1800000
14
+ on:
15
+ passed:
16
+ target: $terminal
17
+ terminalStatus: completed
18
+ failed:
19
+ target: $terminal
20
+ terminalStatus: failed
package/CHANGELOG.md CHANGED
@@ -6,6 +6,23 @@ All notable user-facing changes are documented here. The project follows [Semant
6
6
 
7
7
  ### Added
8
8
 
9
+ - **A live agent step uses a configurable one-shot timeout, and a cancelling run recovers when its child has already exited.**
10
+ The bound is the step `timeoutMs`, or the project `limits.agentStepTimeoutMs`
11
+ when the step omits it (minimum 60 seconds, default one hour). A wider step
12
+ is refused at prerequisites (`step_unsupported`, field `timeoutMs`). The
13
+ effective value is written on the one-shot evidence. A `cancelling` run whose
14
+ executing attempt's child already exited settles `executing_unrecorded`.
15
+ Admission is released when a drive closes with a handoff, so a later drive
16
+ is admitted, and `runs status` names the attempt. `implement-only`,
17
+ `review-arch-only`, and `review-cli-only` are one-step workflows, driven with
18
+ `kxm lane run <unit> --workflow <id> --brief <file>`. See
19
+ [kxm lane](docs/reference/cli-reference.md#kxm-lane),
20
+ [runs status](docs/reference/cli-reference.md#kxm-runs-status),
21
+ [project limits](docs/reference/config-reference.md#kxmprojectyaml-kxmprojectv1),
22
+ [step fields](docs/reference/config-reference.md#step-fields),
23
+ [developer workflows](docs/reference/workflow-catalog.md#repository-developer-workflows),
24
+ and the [transport recipes](docs/contributing/assignment-runner.md#transport-only-recipes).
25
+
9
26
  - **`kxm land` verifies, regenerates docs, and squash-merges the current branch.**
10
27
  The stages are `verify`, `docs`, `push`, `pr`, `rebase`, `unblock`, `merge`,
11
28
  `release`, and `milestone`. `npm run verify` is the first stage and is not
@@ -30,9 +47,9 @@ All notable user-facing changes are documented here. The project follows [Semant
30
47
  and `cancel`. The `just worktree` and `just worktree-drop` recipes now call
31
48
  those verbs. The refusals a user can see are `lane_exists`, `lane_missing`,
32
49
  `lane_base_unresolved`, `lane_dirty`, `lane_run_open`, `brief_unreadable` and
33
- `brief_and_prompt`. A live writer step through `kxm lane run` is still
34
- bounded by the Runtime's 120 second one-shot timeout until the configurable
35
- limit lands. See the
50
+ `brief_and_prompt`. A live writer step through `kxm lane run` is bounded by
51
+ the step's `timeoutMs` or the project's `limits.agentStepTimeoutMs`, default
52
+ one hour. See the
36
53
  [CLI reference](docs/reference/cli-reference.md#kxm-lane).
37
54
 
38
55
  - **The tailnet docs site is built and served with `kxm docs build` and `kxm docs serve`.**
@@ -313,10 +313,21 @@ It writes `recording-resolved.json` in the record directory. It never changes
313
313
 
314
314
  ## Transport-only recipes
315
315
 
316
- `just impl|plan|review-arch|review-cli` and `just dispatch` send one
317
- `kxm.harness-request.v1` envelope through `scripts/harness-run.mjs` and print a
318
- `kxm.harness-result.v2` envelope. They are harness transport only. They mint no
319
- assignment, witness or acceptance proof, so their output cannot be accepted.
316
+ Drive a one-step workflow in a lane. Each command writes a drive receipt and
317
+ the checkout fingerprint. `just impl`, `just plan`, `just review-arch`,
318
+ `just review-cli`, and `just impl-bg` are retired in favor of these. The
319
+ recipes stay in the justfile until one real unit has been driven this way.
320
+
321
+ ```bash
322
+ kxm lane run <unit> --workflow implement-only --brief <file>
323
+ kxm lane run <unit> --workflow review-arch-only --brief <file>
324
+ kxm lane run <unit> --workflow review-cli-only --brief <file>
325
+ ```
326
+
327
+ `just dispatch` still sends one `kxm.harness-request.v1` envelope through
328
+ `scripts/harness-run.mjs` and prints a `kxm.harness-result.v2` envelope. It
329
+ mints no assignment, witness or acceptance proof, so its output cannot be
330
+ accepted. The retired recipes did the same.
320
331
 
321
332
  ### Preflight refusals
322
333
 
@@ -1431,7 +1431,7 @@ Refusals (exit 1): `lane_missing`, `lane_dirty`, `lane_run_open`, `lane_git_fail
1431
1431
 
1432
1432
  Creates the lane when the record is absent (same rules as `create`), refuses `lane_run_open` when the last run is not settled, then runs the same path as `kxm run --lane <unit> --brief <file>` and `kxm runs drive <runId> --lane <unit>`. `--wait` and `--timeout-ms` are passed through. The run id is stored on the record. Prints the run envelope and the drive result. That open-run check may start the Runtime supervisor; `--dry-run` only attaches to a supervisor that is already running. `kxm lane status` never starts the supervisor.
1433
1433
 
1434
- `--brief` is required. `--workflow` defaults to the lane project's `defaultWorkflow`. `--base` applies only when the lane is created. A live writer step through this verb is subject to the Runtime's one-shot process timeout, which is 120 seconds until `limits.agentStepTimeoutMs` lands, so long implementation briefs should use `just impl-bg` until then (see section 4 of `plans/plan-lane-cli.md`).
1434
+ `--brief` is required. `--workflow` defaults to the lane project's `defaultWorkflow`. `--base` applies only when the lane is created. A live agent step uses the step `timeoutMs` when it is set, otherwise the project `limits.agentStepTimeoutMs` (default 3,600,000). This repository's `implement-only`, `review-arch-only`, and `review-cli-only` workflows are the lane forms of the retired transport recipes.
1435
1435
 
1436
1436
  Refusals (exit 1): `brief_unreadable`, `lane_unit_invalid`, `lane_exists`, `lane_base_unresolved`, `lane_run_open`, `lane_git_failed`, `lane_not_project`, `lanes_unreadable`.
1437
1437
 
@@ -165,6 +165,7 @@ makes a directory a KXM project. Parser: `loadKxmProject` in
165
165
  | `limits.maxConcurrentRuns` | Integer, 1 to 128 | Optional, `1` | Runtime admission. A changed bound is refused (`scheduler_policy_conflict`) while admitted or queued runs still use the previous one. |
166
166
  | `limits.maxRunDurationMs` | Integer, 0 to 31,536,000,000 | Optional | Runtime. Combined with the workflow's own value; the smaller one wins. |
167
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 |
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
170
  The Runtime binds one project `id` to one control root per state root, so a
170
171
  second checkout with the same ID is refused with `project_home_conflict`.
@@ -555,7 +556,7 @@ Duration budgets use the wall clock. `maxRunDurationMs` counts from the time the
555
556
  | `signal` | Identifier | Required for `wait` | Compiled and diffed; the Runtime does not match signals to wait steps yet |
556
557
  | `model` | Model selector | Optional | Intersected with each allowed agent's own model ceiling; an empty intersection is `model_selector_incompatible`. Live route resolution ignores it. The Runtime refuses it on gate steps. |
557
558
  | `maxAttempts` | Integer, 1 to 20 | Optional, `1` | Entering the step again after this many attempts fails the run (`budget_step_attempts`) |
558
- | `timeoutMs` | Integer, 0 to 31,536,000,000 | Optional | Not `0`. Gate steps: refused for `artifacts-exist` gates or below the gate's `timeoutMs`. Other kinds: unused; the producer times out at 120 s |
559
+ | `timeoutMs` | Integer, 0 to 31,536,000,000 | Optional | Not `0`. Gate steps: refused for `artifacts-exist` gates or below the gate's `timeoutMs`. Agent and moa steps: the one-shot spawn uses this value when it is at most `limits.agentStepTimeoutMs`; a wider value is refused (`step_unsupported`, field `timeoutMs`). When the step omits it, the project limit applies (default 3,600,000). The process default of 120 seconds is only the last resort when neither is set |
559
560
  | `repositories` | Map of repository ID to `none`, `read`, or `write` | Optional | IDs must be declared (`repository_unknown`); may not exceed the agent's ceiling (`repository_scope_expansion`) |
560
561
  | `tools` | `{preset, allow, deny}` | Optional | Must keep the agent's preset and denials and allow only tools the agent allows (`tool_scope_expansion`). The Runtime refuses steps that declare `tools`. |
561
562
  | `secrets` | `[{ref, as, required}]` | Optional | Only refs the agent grants (`secret_scope_expansion`). The Runtime refuses steps that declare `secrets`. |
@@ -1090,6 +1090,16 @@ This cross-reference points each software and security workflow at the KXM pages
1090
1090
 
1091
1091
  `kxm run land --dry-run --json` may be refused by live prerequisites until gate-only workflows are supported. The command `kxm land` runs the same stages without a run receipt.
1092
1092
 
1093
+ ## Repository developer workflows
1094
+
1095
+ These three files live in this repository's `.kxm/workflows`. `kxm init` does not write them.
1096
+
1097
+ | Workflow | Replaces |
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. |
1102
+
1093
1103
  ## Related
1094
1104
 
1095
1105
  - [Workflow definitions](workflow-definitions.md): write a webhook or Runtime workflow for these stages
@@ -271,7 +271,7 @@ A Runtime workflow is a YAML file whose name is its ID. The [configuration file
271
271
  | Transitions | `on` is required on every step. `$terminal` needs `terminalStatus` (`completed`, `failed` or `cancelled`). Each back-edge needs its own `maxTransitions`, plus `limits.maxTransitions` | [Transitions and outcomes](config-reference.md#transitions-and-outcomes) |
272
272
  | Gate outcome keys | An `expect: pass` gate produces `passed` or `implementation-failure`; an `expect: fail` gate produces `passed` or `repro-missing`. Declare both produced outcomes | [Transitions and outcomes](config-reference.md#transitions-and-outcomes) |
273
273
  | `gate_outcome_impossible` | Refused at load when a gate step declares an outcome it never produces, such as `failed`, and omits one it produces. `gate_outcome_renamed` catches underscore spellings | [Transitions and outcomes](config-reference.md#transitions-and-outcomes) |
274
- | Agent steps | The model returns a JSON `outcome` from the step's declared keys; anything else becomes `failed`, so declare `failed` | [Transitions and outcomes](config-reference.md#transitions-and-outcomes) |
274
+ | Agent steps | The model returns a JSON `outcome` from the step's declared keys; anything else becomes `failed`, so declare `failed`. `timeoutMs` bounds the one-shot spawn for `agent` and `moa` steps, and must not be wider than the project `limits.agentStepTimeoutMs` | [Step fields](config-reference.md#step-fields) |
275
275
  | Not executed yet | Some valid fields make the Runtime hand the run off (`step_unsupported`, `gate_unsupported`, `limit_unsupported`) instead of executing | [Steps the Runtime does not execute yet](config-reference.md#steps-the-runtime-does-not-execute-yet) |
276
276
 
277
277
  `kxm workflow add bug-fix --template implement-and-verify` writes a valid starting file; `dual-critic-review` and `spec-and-plan` are also available. IDs are flat filename-derived slugs, not catalog paths such as `software-engineering/bug-fix`. Installation validates YAML/schema/transitions before writing, including under `--dry-run`. `kxm run <workflow>` creates a run and reports live prerequisites and separate `runs drive/status/receipt` commands. Current live one-shot profiles are read-only, so a writer template can validate but cannot execute live; `task run` refuses incompatible work before creating a run or changing the task. Simulation remains explicitly available and is not proof of implementation. See [`kxm run`](cli-reference.md#kxm-run) and [`kxm runs`](cli-reference.md#kxm-runs).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextmind/kxm",
3
- "version": "0.7.123",
3
+ "version": "0.7.124",
4
4
  "description": "KXM local-first multi-agent orchestration and operator dashboard",
5
5
  "type": "module",
6
6
  "author": "KontextMind",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "kxm",
4
4
  "displayName": "KXM",
5
- "version": "0.7.123",
5
+ "version": "0.7.124",
6
6
  "description": "Headless multi-agent orchestration, durable workflows, and a live operator dashboard for Pi and Claude Code",
7
7
  "author": {
8
8
  "name": "KontextMind",
@@ -21375,13 +21375,16 @@ function objectValue3(value) {
21375
21375
  function kxmProjectAdmissionLimits(bundle) {
21376
21376
  const limits = objectValue3(bundle.project.value.limits);
21377
21377
  const maxConcurrentRuns = typeof limits?.maxConcurrentRuns === "number" && Number.isInteger(limits.maxConcurrentRuns) && limits.maxConcurrentRuns >= 1 ? limits.maxConcurrentRuns : 1;
21378
+ const declared = limits?.agentStepTimeoutMs;
21379
+ const agentStepTimeoutMs = typeof declared === "number" && Number.isInteger(declared) && declared >= KXM_MIN_AGENT_STEP_TIMEOUT_MS ? declared : KXM_DEFAULT_AGENT_STEP_TIMEOUT_MS;
21378
21380
  return {
21379
21381
  maxConcurrentRuns,
21380
21382
  ...typeof limits?.maxRunDurationMs === "number" ? { maxRunDurationMs: limits.maxRunDurationMs } : {},
21381
- ...typeof limits?.maxAgentTimeMs === "number" ? { maxAgentTimeMs: limits.maxAgentTimeMs } : {}
21383
+ ...typeof limits?.maxAgentTimeMs === "number" ? { maxAgentTimeMs: limits.maxAgentTimeMs } : {},
21384
+ agentStepTimeoutMs
21382
21385
  };
21383
21386
  }
21384
- var RUNTIME_EPOCH_NS;
21387
+ var KXM_DEFAULT_AGENT_STEP_TIMEOUT_MS, KXM_MIN_AGENT_STEP_TIMEOUT_MS, RUNTIME_EPOCH_NS;
21385
21388
  var init_runtime_service = __esm({
21386
21389
  "plugins/kxm/src/runtime-service.ts"() {
21387
21390
  "use strict";
@@ -21391,6 +21394,8 @@ var init_runtime_service = __esm({
21391
21394
  init_engine_plan();
21392
21395
  init_runtime_owner();
21393
21396
  init_runtime_store();
21397
+ KXM_DEFAULT_AGENT_STEP_TIMEOUT_MS = 36e5;
21398
+ KXM_MIN_AGENT_STEP_TIMEOUT_MS = 6e4;
21394
21399
  RUNTIME_EPOCH_NS = process.hrtime.bigint();
21395
21400
  }
21396
21401
  });
@@ -21400,6 +21405,7 @@ var TEXT_LIMIT, ARGV_LIMIT, RECORD_LIMIT;
21400
21405
  var init_oneshot_evidence = __esm({
21401
21406
  "plugins/kxm/src/oneshot-evidence.ts"() {
21402
21407
  "use strict";
21408
+ init_bindings();
21403
21409
  TEXT_LIMIT = 4 * 1024 * 1024;
21404
21410
  ARGV_LIMIT = 64 * 1024;
21405
21411
  RECORD_LIMIT = 16 * 1024 * 1024;
@@ -23195,6 +23201,15 @@ function resolveProducerRoute(projectRoot, step, agentId) {
23195
23201
  const model = selector.slice(slash + 1);
23196
23202
  return { provider, model, selector };
23197
23203
  }
23204
+ function unsupportedAgentStepTimeout(step, limitMs) {
23205
+ if (step.kind !== "agent" && step.kind !== "moa") return void 0;
23206
+ if (step.timeoutMs === void 0 || step.timeoutMs <= limitMs) return void 0;
23207
+ return {
23208
+ reason: "step_unsupported",
23209
+ field: "timeoutMs",
23210
+ detail: "step timeoutMs is wider than project limits.agentStepTimeoutMs"
23211
+ };
23212
+ }
23198
23213
  function kxmLiveRunPrerequisites(bundle, workflowId, projectRoot) {
23199
23214
  const workflow = bundle.workflows.get(workflowId);
23200
23215
  if (!workflow) throw runtimeError("run_workflow_unknown", workflowId, `workflow ${workflowId} does not exist in this project`);
@@ -23213,7 +23228,8 @@ function kxmLiveRunPrerequisites(bundle, workflowId, projectRoot) {
23213
23228
  for (const transition2 of Object.values(step.transitions)) {
23214
23229
  if (transition2.to === "step") pending.push(transition2.target);
23215
23230
  }
23216
- const unsupported = step.kind === "gate" ? unsupportedGateStep(plan, step, envelope, { projectRoot }) ?? starterGatePrerequisite(step, envelope.gates, projectRoot) : unsupportedStep(plan, step, "oneshot");
23231
+ const limitMs = envelope.projectLimits.agentStepTimeoutMs ?? KXM_DEFAULT_AGENT_STEP_TIMEOUT_MS;
23232
+ const unsupported = step.kind === "gate" ? unsupportedGateStep(plan, step, envelope, { projectRoot }) ?? starterGatePrerequisite(step, envelope.gates, projectRoot) : unsupportedAgentStepTimeout(step, limitMs) ?? unsupportedStep(plan, step, "oneshot");
23217
23233
  if (unsupported) {
23218
23234
  prerequisites.push({ ...unsupported, stepId });
23219
23235
  continue;
@@ -23533,6 +23549,7 @@ var init_engine = __esm({
23533
23549
  init_context_packet();
23534
23550
  init_engine_compile();
23535
23551
  init_harness();
23552
+ init_oneshot_evidence();
23536
23553
  init_engine_fold();
23537
23554
  init_engine_plan();
23538
23555
  init_dispatch_context();
@@ -23556,7 +23573,6 @@ var init_oneshot_producer = __esm({
23556
23573
  "plugins/kxm/src/oneshot-producer.ts"() {
23557
23574
  "use strict";
23558
23575
  init_oneshot_evidence();
23559
- init_bindings();
23560
23576
  init_oneshot_process();
23561
23577
  init_oneshot_process();
23562
23578
  init_harness();
@@ -26990,7 +27006,10 @@ function formatDriveStatusLine(runStatus, drive) {
26990
27006
  }
26991
27007
  function formatRunStatusLine(run, drive) {
26992
27008
  const reason = typeof drive?.receipt?.settlement?.reason === "string" ? drive.receipt.settlement.reason : "";
26993
- const statusLabel = run.status === "cancelled" ? formatCancelledStatus(reason) : run.status;
27009
+ const handoff = drive?.receipt?.settlement?.handoff;
27010
+ const attemptId = typeof handoff?.attemptId === "string" ? handoff.attemptId : "";
27011
+ const handoffReason = typeof handoff?.reason === "string" ? handoff.reason : "";
27012
+ const statusLabel = run.status === "cancelled" ? formatCancelledStatus(reason) : run.status === "cancelling" && attemptId.length > 0 && handoffReason.length > 0 ? `cancelling (attempt ${attemptId}, ${handoffReason})` : run.status;
26994
27013
  return `run ${run.runId}: ${statusLabel} (workflow ${run.workflowId}, updated ${run.updatedAt})`;
26995
27014
  }
26996
27015
  async function cmdKxmRunStatus(runtime, runId) {
@@ -17313,7 +17313,7 @@ function sessionTokenFixHint(policy) {
17313
17313
  }
17314
17314
 
17315
17315
  // plugins/kxm/src/mcp-server.ts
17316
- var VERSION = "0.7.123";
17316
+ var VERSION = "0.7.124";
17317
17317
  var CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
17318
17318
  var inbox = /* @__PURE__ */ new Map();
17319
17319
  var notifiedInbox = /* @__PURE__ */ new Set();