@kontextmind/kxm 0.7.91 → 0.7.93
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/workflows/default.yaml +1 -1
- package/CHANGELOG.md +212 -0
- package/README.md +3 -0
- package/docs/README.md +3 -0
- package/docs/agent-skills.md +123 -60
- package/docs/architecture.md +5 -2
- package/docs/cli-reference.md +3527 -0
- package/docs/config-reference.md +1943 -0
- package/docs/configuration.md +30 -4
- package/docs/continuous-improvement.md +122 -10
- package/docs/contracts/routing.md +95 -11
- package/docs/harness-routing.md +616 -0
- package/docs/kxm-handbook.md +106 -19
- package/docs/templates/README.md +1 -1
- package/docs/test-matrix.md +12 -6
- package/docs/troubleshooting.md +2 -2
- package/examples/project/.kxm/workflows/fix.yaml +1 -1
- package/examples/project/.kxm/workflows/improve.yaml +1 -1
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +9 -10
- package/plugins/kxm/README.md +238 -56
- package/plugins/kxm/dist/claude-hook.js +10083 -0
- package/plugins/kxm/dist/cli.js +2487 -1848
- package/plugins/kxm/dist/client.js +64 -0
- package/plugins/kxm/dist/core.js +102 -9
- package/plugins/kxm/dist/extension.js +210 -68
- package/plugins/kxm/dist/mcp-server.js +217 -40
- package/plugins/kxm/dist/runtime-supervisor.js +1628 -157
- package/plugins/kxm/dist/runtime.js +1874 -298
- package/plugins/kxm/dist/server.js +416 -82
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/hints.json +1 -1
- package/plugins/kxm/skills/kxm/SKILL.md +48 -24
- package/plugins/kxm/skills/kxm/references/protocol.md +3 -3
- package/plugins/kxm/skills/kxm-context-memory/SKILL.md +67 -21
- package/plugins/kxm/skills/kxm-definitions/SKILL.md +9 -0
- package/plugins/kxm/skills/kxm-harness-auth/SKILL.md +82 -16
- package/plugins/kxm/skills/kxm-harvest/SKILL.md +1 -1
- package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +55 -27
- package/plugins/kxm/skills/kxm-insights/SKILL.md +1 -1
- package/plugins/kxm/skills/kxm-mind/SKILL.md +2 -2
- package/plugins/kxm/skills/{kxm-setup → kxm-mind-setup}/SKILL.md +4 -4
- package/plugins/kxm/skills/kxm-peer/SKILL.md +68 -93
- package/plugins/kxm/skills/kxm-project-setup/SKILL.md +156 -23
- package/plugins/kxm/skills/kxm-projects/SKILL.md +1 -1
- package/plugins/kxm/skills/kxm-protocol/SKILL.md +1 -1
- package/plugins/kxm/skills/kxm-query/SKILL.md +1 -1
- package/plugins/kxm/skills/kxm-routing-improve/SKILL.md +74 -15
- package/plugins/kxm/skills/kxm-runs/SKILL.md +46 -17
- package/plugins/kxm/skills/kxm-session/SKILL.md +64 -36
- package/plugins/kxm/skills/kxm-skill-lifecycle/SKILL.md +44 -15
- package/plugins/kxm/skills/kxm-tasks/SKILL.md +16 -4
- package/plugins/kxm/skills/kxm-triage/SKILL.md +1 -1
- package/plugins/kxm/skills/kxm-work/SKILL.md +1 -1
- package/plugins/kxm/skills/kxm-workflow/SKILL.md +60 -19
- package/plugins/kxm/src/arbiter.ts +67 -22
- package/plugins/kxm/src/autocomplete.ts +1 -1
- package/plugins/kxm/src/claude-hook.ts +192 -0
- package/plugins/kxm/src/cli/project.ts +11 -5
- package/plugins/kxm/src/cli/system.ts +85 -13
- package/plugins/kxm/src/cli/types.ts +4 -1
- package/plugins/kxm/src/cli/workflows.ts +18 -16
- package/plugins/kxm/src/cli.ts +23 -13
- package/plugins/kxm/src/client.ts +15 -4
- package/plugins/kxm/src/commands.ts +19 -9
- package/plugins/kxm/src/config.ts +42 -7
- package/plugins/kxm/src/context-packet.ts +14 -2
- package/plugins/kxm/src/context.ts +16 -5
- package/plugins/kxm/src/dispatch-context.ts +286 -0
- package/plugins/kxm/src/engine-plan.ts +40 -0
- package/plugins/kxm/src/engine.ts +138 -6
- package/plugins/kxm/src/hub-env.ts +17 -1
- package/plugins/kxm/src/hub.ts +92 -29
- package/plugins/kxm/src/improve-sources.ts +228 -0
- package/plugins/kxm/src/improve.ts +325 -140
- package/plugins/kxm/src/local-snapshot.ts +101 -42
- package/plugins/kxm/src/mcp-server.ts +129 -30
- package/plugins/kxm/src/memory.ts +43 -20
- package/plugins/kxm/src/project-config.ts +25 -0
- package/plugins/kxm/src/protocol.ts +11 -0
- package/plugins/kxm/src/relevance.ts +138 -0
- package/plugins/kxm/src/retrospective.ts +16 -10
- package/plugins/kxm/src/runtime-service.ts +8 -1
- package/plugins/kxm/src/runtime-supervisor.ts +16 -2
- package/plugins/kxm/src/session-token-hint.ts +17 -0
- package/plugins/kxm/src/suggest.ts +7 -7
- package/plugins/kxm/src/workflow-manager.ts +80 -78
- package/plugins/kxm/src/workflow.ts +202 -12
- package/scripts/build-runtime.mjs +7 -1
- package/scripts/check-generated.mjs +1 -0
- package/scripts/emit-codex-artifacts.mjs +1 -1
|
@@ -1,53 +1,81 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: kxm-session
|
|
3
|
-
description:
|
|
3
|
+
description: Read KXM session and hub status with kxm session status and kxm hub view, create a session manifest with kxm session start, open kxm dash screens, and lay out workflows with kxm studio layout. Use at the start of a session, when asked what is in flight, or when opening the dashboard. kxm session brief, kxm session stop, and kxm studio serve are operator steps because they save a 24-hour session token, stop the hub, or open a listener.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# KXM session
|
|
6
|
+
# KXM session
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Start a session by reading status. The agent steps below write no token and
|
|
9
|
+
start no process.
|
|
9
10
|
|
|
10
|
-
##
|
|
11
|
+
## Agent steps
|
|
11
12
|
|
|
12
|
-
|
|
|
13
|
+
| Command | Purpose | Options / arguments |
|
|
13
14
|
|---|---|---|
|
|
14
|
-
|
|
|
15
|
-
|
|
|
16
|
-
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
kxm hub
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
15
|
+
| `kxm session status` | Session claims and recovery envelopes | `--json` |
|
|
16
|
+
| `kxm hub view` | Hub `/health` and `/ready`; exits 1 when the hub is down | `--json` |
|
|
17
|
+
| `kxm session start` | Create an agent/gate or workflow session manifest; launches nothing | `--id`, `--workflow`, `--mix`, `--json` |
|
|
18
|
+
| `kxm dash` | Live screens for agents, tasks, workflows, and plans | `--screen agents\|tasks\|workflows\|plans\|inbox\|procs\|spend` |
|
|
19
|
+
| `kxm studio layout [workflowPath]` | DAG, stepper, and swimlane layout JSON for a workflow | `--json` |
|
|
20
|
+
|
|
21
|
+
At the start of a session, run `kxm session status` and `kxm hub view`. In a
|
|
22
|
+
repository with no session token file both leave the user config directory
|
|
23
|
+
and the Git tree unchanged. `kxm session status` prints
|
|
24
|
+
`0 session claim(s), 0 recovery envelope(s)` on a fresh project, and
|
|
25
|
+
`kxm hub view` prints `hub health=false ready=false · loopback hub` and exits 1
|
|
26
|
+
while the hub is down.
|
|
27
|
+
|
|
28
|
+
## Hub binding
|
|
29
|
+
|
|
30
|
+
| Track | When | What to do |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| Local only | `kxm init` without a hub | Work with runs and Git memory; skip hub status chrome |
|
|
33
|
+
| Local hub | The user ran `kxm hub bind http://127.0.0.1:7331` | Read status with `kxm hub view` |
|
|
34
|
+
| Remote hub | The user ran `kxm hub bind <https-url>` | Binds when a credential resolves; otherwise it fails closed with `hub_bind_unauthenticated` |
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
`KXM_SERVER_URL` overrides a bound URL. Binding is an operator step owned by
|
|
37
|
+
`kxm-hub-ops`.
|
|
36
38
|
|
|
37
39
|
## Harness support (fail closed)
|
|
38
40
|
|
|
39
|
-
| Harness | Picker | Status line |
|
|
41
|
+
| Harness | Picker | Status line | First reply |
|
|
40
42
|
|---|---|---|---|
|
|
41
|
-
| Pi TUI | Yes, extension | Yes, `setStatus`
|
|
42
|
-
| Pi RPC / worker | No |
|
|
43
|
-
| Claude Code | No
|
|
44
|
-
| Codex, Kimi, Gemini, DeepSeek | Unknown | None unless that CLI documents a status command |
|
|
43
|
+
| Pi TUI | Yes, kxm extension | Yes, `setStatus` plus widget | Load the kxm extension (default from the package) |
|
|
44
|
+
| Pi RPC / worker | No | Only if UI helpers exist; never a picker | Skip chrome |
|
|
45
|
+
| Claude Code | No picker | The plugin's SessionStart hook adds a short KXM brief only in projects with `.kxm`; a statusLine is optional and an operator step | Run `kxm session status` and `kxm hub view` |
|
|
46
|
+
| Codex, Kimi, Gemini, DeepSeek | Unknown | None unless that CLI documents a status command | Run `kxm session status` and `kxm hub view` |
|
|
47
|
+
|
|
48
|
+
Interactive Pi TUI: on `startup`, `/new`, and `/fork`, the kxm extension offers
|
|
49
|
+
recent tasks and plans and paints the footer and widget, including a `ship`
|
|
50
|
+
line (dirty tree, local commits, PR after CI). `/kxm` reopens the picker,
|
|
51
|
+
`/kxm status` refreshes chrome only, and `/kxm hub` is the hub view. Workers,
|
|
52
|
+
RPC, and print mode never prompt. `KXM_SESSION_BRIEF=off` disables the picker
|
|
53
|
+
only.
|
|
45
54
|
|
|
46
55
|
This skill never grants tools or permissions.
|
|
47
56
|
|
|
48
|
-
## Operator
|
|
57
|
+
## Operator steps
|
|
58
|
+
|
|
59
|
+
Ask the user to run these in their own terminal.
|
|
49
60
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
61
|
+
Until kxm session brief stops minting tokens, running it saves a 24-hour
|
|
62
|
+
operator session token; when that token expires every kxm_* tool fails with
|
|
63
|
+
tool_policy_denied. Its plain output prints a Session token line, so never
|
|
64
|
+
paste it into a conversation.
|
|
65
|
+
|
|
66
|
+
| Command | Purpose | Options |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| `kxm session brief` | Recent hub tasks (workflow runs) and plans (journal `plan` rows) from the local hub store; every form saves the session token | `--status` (status line only), `--json` |
|
|
69
|
+
| `kxm session token --status` | Report the active session token | `--json` |
|
|
70
|
+
| `kxm session token --clear` | Delete the session token file | `--json` |
|
|
71
|
+
| `kxm session stop` | Request managed hub and worker shutdown | `--wait-ms <ms>` |
|
|
72
|
+
| `kxm studio serve` | Start the Web Studio listener (default `http://localhost:4242`) | `--port`, `--host`, `--token` |
|
|
73
|
+
|
|
74
|
+
- `kxm session token --status` reports
|
|
75
|
+
`No active session token found in env or disk` for an expired or malformed
|
|
76
|
+
file, even though that file still blocks every kxm_* tool. `--clear` is the
|
|
77
|
+
fix for such a file.
|
|
78
|
+
- Claude Code statusLine: the user may point `statusLine` at
|
|
79
|
+
`kxm session brief --status`, which saves the same 24-hour token.
|
|
80
|
+
- Pi operator loop: `kxm hub view`, then `kxm session brief` or Pi `/kxm`, pick
|
|
81
|
+
a task or plan or start fresh, and keep `kxm dash` open for a live view.
|
|
@@ -1,31 +1,60 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: kxm-skill-lifecycle
|
|
3
|
-
description: Govern candidate
|
|
3
|
+
description: Govern KXM skill candidates. Create one from verified runs, journal entries, receipts, or a kxm improve skill candidate, record static-review, sandbox, functional and safety evaluations, and list or verify pinned hashes, while promotion and rejection stay a non-author decision. Use when turning a repeated practice into a reusable skill. Not for editing the bundled kxm-* plugin skills.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# KXM
|
|
6
|
+
# KXM governed skills
|
|
7
7
|
|
|
8
|
-
This is the governed candidate lifecycle
|
|
9
|
-
suite. Bundled skills are authored in Git and mirrored to
|
|
10
|
-
Do not invent `candidate`, `quarantine`, `rollback`,
|
|
8
|
+
This is the governed candidate lifecycle under `.kxm/skills/`, not the bundled
|
|
9
|
+
`plugins/kxm/skills` suite. Bundled skills are authored in Git and mirrored to
|
|
10
|
+
`.agents/skills`. Do not invent `candidate`, `quarantine`, `rollback`,
|
|
11
|
+
`validate`, or `get` verbs.
|
|
11
12
|
|
|
12
|
-
##
|
|
13
|
+
## Agent steps
|
|
13
14
|
|
|
14
15
|
| Command | Purpose | Options / arguments |
|
|
15
16
|
|---|---|---|
|
|
16
|
-
| `kxm skills create` | Submit a candidate from verified episodes | `--file`, `--name`, `--
|
|
17
|
+
| `kxm skills create` | Submit a candidate from verified episodes | Required `--file`, `--name`, `--created-by`, `--harness`, `--models`; optional `--description`, `--run`, `--journal`, `--receipt`, `--supersedes` |
|
|
17
18
|
| `kxm skills evaluate <skillId>` | Record a protected evaluation | `--kind static-review\|sandbox\|functional\|safety\|optimization`, `--evaluator`, `--fail`, `--score`, `--details` |
|
|
18
|
-
| `kxm skills
|
|
19
|
-
| `kxm skills
|
|
20
|
-
| `kxm skills list` | List skills by state | `--state candidate\|promoted\|quarantined\|rejected` |
|
|
21
|
-
| `kxm skills verify <skillId>` | Verify pinned content hash | `--state candidate\|promoted\|quarantined\|rejected` |
|
|
19
|
+
| `kxm skills list` | List skills by state (default `promoted`) | `--state candidate\|promoted\|quarantined\|rejected` |
|
|
20
|
+
| `kxm skills verify <skillId>` | Verify the pinned content hash | `--state candidate\|promoted\|quarantined\|rejected` |
|
|
22
21
|
|
|
23
22
|
```bash
|
|
23
|
+
kxm skills create --file /tmp/retry-backoff/SKILL.md --name retry-backoff --created-by agent_writer --harness claude-code --models claude/fable --run run_1 --receipt receipt:run_1/verify --dry-run --json
|
|
24
24
|
kxm skills list --state candidate --json
|
|
25
25
|
kxm skills evaluate skill_123 --kind static-review --evaluator eval-1.0.0 --json
|
|
26
|
-
kxm skills
|
|
27
|
-
kxm skills verify skill_123 --state promoted --json
|
|
26
|
+
kxm skills verify skill_123 --state candidate --json
|
|
28
27
|
```
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
A failed `functional` or `safety` evaluation quarantines the candidate
|
|
30
|
+
automatically. Promotion needs passing `static-review`, `sandbox`,
|
|
31
|
+
`functional`, and `safety` evaluations.
|
|
32
|
+
|
|
33
|
+
## From an improvement candidate
|
|
34
|
+
|
|
35
|
+
`kxm improve report` proposes a `skill` candidate as a diff that adds a
|
|
36
|
+
`SKILL.md` draft (`kxm-routing-improve`).
|
|
37
|
+
|
|
38
|
+
1. Review the proposed `SKILL.md` draft with the user and rewrite it into
|
|
39
|
+
real instructions.
|
|
40
|
+
2. Save it outside `.kxm/skills`, for example under `/tmp/<name>/SKILL.md`.
|
|
41
|
+
3. Run
|
|
42
|
+
`kxm skills create --file <draft> --name <name> --created-by <id> --harness claude-code --models <models> --run <ids> --receipt <refs>`.
|
|
43
|
+
4. Record the evaluations above.
|
|
44
|
+
|
|
45
|
+
Never apply the candidate diff into `.kxm/skills`. `kxm skills list --state candidate`
|
|
46
|
+
ignores a hand-written `.kxm/skills/candidates/<slug>/SKILL.md`; only
|
|
47
|
+
`kxm skills create` registers a candidate with its pinned hash and history.
|
|
48
|
+
|
|
49
|
+
## Operator steps
|
|
50
|
+
|
|
51
|
+
Promotion and rejection belong to a non-author: the user or another
|
|
52
|
+
authorized reviewer, never the agent that created the candidate.
|
|
53
|
+
|
|
54
|
+
| Command | Purpose | Options / arguments |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `kxm skills promote <skillId>` | Promote a candidate that passed the required evaluations; writes a patch for review | `--decided-by` (must differ from the author), `--evidence`, `--reason` |
|
|
57
|
+
| `kxm skills reject <skillId>` | Reject a candidate; history is retained | `--decided-by`, `--reason` |
|
|
58
|
+
|
|
59
|
+
Promotion requires durable evidence. A candidate cannot grant tools, skip
|
|
60
|
+
review, or auto-promote bundled skills.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: kxm-tasks
|
|
3
|
-
description: Recommend workflows and manage goals
|
|
3
|
+
description: Recommend workflows and manage goals and tasks with explicit SCM and tracker boundaries. Use when asked what workflow fits, to plan work as goals and tasks, or to sync with GitHub or Jira. Run a kxm suggest workflow ID only after kxm workflow definitions lists it.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# KXM
|
|
6
|
+
# KXM suggest, goals, and tasks
|
|
7
7
|
|
|
8
8
|
Bind SCM and issue trackers from this repo's conventions. Implemented today:
|
|
9
9
|
GitHub and Jira. An unimplemented tracker fails closed. Do not invent
|
|
@@ -16,7 +16,7 @@ GitHub and Jira. An unimplemented tracker fails closed. Do not invent
|
|
|
16
16
|
| `kxm suggest <prompt...>` | Recommend workflow, area, roles, and skills | `--json` |
|
|
17
17
|
| `kxm goal create <title>` | Create a project goal | `--area`, `--metric`, `--target-date` |
|
|
18
18
|
| `kxm goal list` | List project goals | `--json` |
|
|
19
|
-
| `kxm task create <title>` | Create a task | `--goal`, `--objective`, `--workflow`, `--tracker github\|jira`, `--issue
|
|
19
|
+
| `kxm task create <title>` | Create a task | `--goal`, `--objective`, `--workflow`, `--tracker github\|jira`, `--issue <number-or-key>` |
|
|
20
20
|
| `kxm task list` | List project tasks | `--goal`, `--status todo\|in_progress\|blocked\|in_review\|done` |
|
|
21
21
|
| `kxm task get <taskId>` | Task details and linked workflow status | `--json` |
|
|
22
22
|
| `kxm task run <taskId>` | Launch a workflow run driven by this task | `--json` |
|
|
@@ -24,10 +24,22 @@ GitHub and Jira. An unimplemented tracker fails closed. Do not invent
|
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
26
|
kxm suggest "implement trusted roster policy brakes" --json
|
|
27
|
+
kxm workflow definitions
|
|
27
28
|
kxm goal create "Land the skills suite" --area software-engineering --json
|
|
28
29
|
kxm task create "Repair trust loader" --goal goal_1 --tracker github --issue 127 --json
|
|
29
30
|
kxm task list --status in_progress --json
|
|
30
31
|
kxm task sync task_1 --json
|
|
31
32
|
```
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
## Suggested workflows
|
|
35
|
+
|
|
36
|
+
`kxm suggest` picks its workflow ID from a built-in catalog, and that ID may
|
|
37
|
+
not exist in this project. Before running the suggested `kxm run` command,
|
|
38
|
+
confirm that `kxm workflow definitions` lists the ID; otherwise `kxm run`
|
|
39
|
+
fails with `run_workflow_unknown`. Pick a listed workflow instead, or write
|
|
40
|
+
one with the user (`kxm-project-setup`).
|
|
41
|
+
|
|
42
|
+
`--issue` on `kxm task create` is a tracker issue number or Jira key, not a
|
|
43
|
+
credential. In this build `kxm task sync` marks only the local task record
|
|
44
|
+
synced; it does not contact GitHub or Jira. Do not silently use GitHub when
|
|
45
|
+
the operator picked an unimplemented tracker.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: kxm-triage
|
|
3
|
-
description:
|
|
3
|
+
description: KontextMind knowledge plane only, the separate kontext CLI and km_ tools, not KXM or this plugin's kxm_* tools. Works the KontextMind review queue with km_review. Use only when the user names KontextMind, the kontext CLI, or a km_ tool.
|
|
4
4
|
license: Apache-2.0
|
|
5
5
|
compatibility: Any agent that can run a shell or MCP client. No vendor-only tools.
|
|
6
6
|
metadata:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: kxm-work
|
|
3
|
-
description: KontextMind
|
|
3
|
+
description: KontextMind knowledge plane only, the separate kontext CLI and km_ tools, not KXM or this plugin's kxm_* tools. Reads and updates KontextMind tracker work state with the km_work and km_handoff tools. Use only when the user names KontextMind, the kontext CLI, or a km_ tool.
|
|
4
4
|
license: Apache-2.0
|
|
5
5
|
compatibility: Any agent that can run a shell or MCP client. No vendor-only tools.
|
|
6
6
|
metadata:
|
|
@@ -1,45 +1,86 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: kxm-workflow
|
|
3
|
-
description:
|
|
3
|
+
description: Work inside a durable KXM workflow run. Read it, record plan, decision, contradiction, error and lesson journal entries, pass stage checkpoints with keyed evidence and peer evidence refs, wait for signed CI or review callbacks, start webhook workflows, and export retrospectives (kxm_workflow_get, kxm_workflow_record, kxm_workflow_checkpoint, kxm_workflow_wait). Use when a workflow run ID is involved or the user asks to checkpoint, gate, or wait on CI.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# KXM
|
|
6
|
+
# KXM workflow and gates
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
Durable workflow runs live on the hub and start from signed webhooks. Read the
|
|
9
|
+
run first (`kxm_workflow_get` or `kxm workflow get <runId>`), record material
|
|
10
|
+
plans, decisions, contradictions, errors, and lessons as you work, and pass
|
|
11
|
+
every stage checkpoint before replying.
|
|
12
|
+
|
|
13
|
+
Peer-reply requirements need durable replied message IDs in
|
|
14
|
+
`--evidence-refs` (MCP `evidenceRefs`). Caller-authored text never satisfies
|
|
15
|
+
peer quorum.
|
|
16
|
+
|
|
17
|
+
`kxm workflow list` and `kxm workflow get` show hub webhook runs. Runs created
|
|
18
|
+
with `kxm run` are Runtime runs; inspect them with `kxm runs list`
|
|
19
|
+
(`kxm-runs`).
|
|
10
20
|
|
|
11
21
|
## Workflow
|
|
12
22
|
|
|
13
23
|
| Command | Purpose | Options / arguments |
|
|
14
24
|
|---|---|---|
|
|
15
|
-
| `kxm workflow list` | List
|
|
16
|
-
| `kxm workflow get <runId>` | Show one run | `--json` |
|
|
17
|
-
| `kxm workflow checkpoint [runId] [stageId] [status] [summary]` | Record a stage result | `--run-id`, `--stage-id`, `--status passed\|warning\|failed`, `--summary`, `--evidence
|
|
18
|
-
| `kxm workflow record [runId] [category] [area] [summary]` | Journal
|
|
19
|
-
| `kxm workflow wait [runId] [stageId] [signalKey] [summary]` | Wait for a signed callback | `--signal-key`, `--timeout-ms`, `--evidence
|
|
20
|
-
| `kxm workflow signal <runId> <signalKey> <status> <summary>` | Resume a wait or KXM run | `[evidence...]`, `--delivery-id` |
|
|
21
|
-
| `kxm workflow start [definitionId]` | POST a signed workflow-start webhook | `--payload
|
|
25
|
+
| `kxm workflow list` | List hub workflow runs in the local store | `--json` |
|
|
26
|
+
| `kxm workflow get <runId>` | Show one run with its stages and journal | `--json` |
|
|
27
|
+
| `kxm workflow checkpoint [runId] [stageId] [status] [summary]` | Record a stage result | `--run-id`, `--stage-id`, `--status passed\|warning\|failed`, `--summary`, `--evidence <json>`, `--evidence-refs <json>` |
|
|
28
|
+
| `kxm workflow record [runId] [category] [area] [summary]` | Journal one of ten categories | `--category`, `--area`, `--stage-id`, `--severity info\|warning\|error`, `--summary`, `--details`, `--evidence <items...>`, `--related-entry-ids <ids...>` |
|
|
29
|
+
| `kxm workflow wait [runId] [stageId] [signalKey] [summary]` | Wait for a signed callback | `--signal-key`, `--summary`, `--timeout-ms`, `--evidence <json>`, `--evidence-refs <json>` |
|
|
30
|
+
| `kxm workflow signal <runId> <signalKey> <status> <summary>` | Resume a wait or unblock a KXM run | `[evidence...]` as `required-key=evidence`, `--delivery-id` |
|
|
31
|
+
| `kxm workflow start [definitionId]` | POST a signed workflow-start webhook | `--payload <json\|@file>`, `--delivery-id`, `--event` |
|
|
22
32
|
| `kxm workflow export <runId>` | Export a proposed retrospective | `--input`, `--out-dir` |
|
|
23
|
-
| `kxm workflow definitions` | List definitions | `--scope all\|global\|local` |
|
|
33
|
+
| `kxm workflow definitions` | List project and global workflow definitions | `--scope all\|global\|local` |
|
|
24
34
|
| `kxm workflow add [workflowId]` | Add a definition | `--file`, `--description`, `--scope`, `--overwrite`, `--pick` |
|
|
25
35
|
| `kxm workflow remove [workflowId]` | Remove a definition | `--scope`, `--pick` |
|
|
26
36
|
| `kxm workflow modify [workflowId]` | Modify a definition | `--description`, `--scope`, `--pick` |
|
|
27
37
|
|
|
38
|
+
```bash
|
|
39
|
+
kxm workflow get run_12345 --json
|
|
40
|
+
kxm workflow checkpoint run_12345 implement passed "Implementation complete" --evidence '{"tests":"npm test passed"}' --json
|
|
41
|
+
kxm workflow wait run_12345 verify github-pr-42-checks "CI running on PR 42" --json
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Journal
|
|
45
|
+
|
|
46
|
+
Categories are `plan`, `decision`, `contradiction`, `error`, `lesson`,
|
|
47
|
+
`observation`, `hypothesis`, `experiment`, `state-change`, and
|
|
48
|
+
`skill-candidate`. A `lesson` or `skill-candidate` requires `--evidence`; the
|
|
49
|
+
hub refuses one without it. Pass `--stage-id` to bind an entry to its stage:
|
|
50
|
+
the hub derives the attempt, and area defaults to the stage's declared area,
|
|
51
|
+
so `kxm workflow record <runId> <category> <summary> --stage-id <id>` works
|
|
52
|
+
without an area. Never supply an attempt. Link a decision or lesson that
|
|
53
|
+
resolves a contradiction with `--related-entry-ids`. The journal covers hub
|
|
54
|
+
webhook runs; a `kxm run` ID is `workflow_not_found`.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
kxm workflow record run_12345 lesson "Flaky test hid a race" --stage-id verify --severity warning --evidence https://ci.example.com/run/42 --json
|
|
58
|
+
kxm workflow record run_12345 decision "Serialize the fixture setup" --stage-id verify --related-entry-ids je_123 --json
|
|
59
|
+
```
|
|
60
|
+
|
|
28
61
|
## Gates
|
|
29
62
|
|
|
30
63
|
| Command | Purpose | Options / arguments |
|
|
31
64
|
|---|---|---|
|
|
32
|
-
| `kxm gate validate` | Parse workflow definitions without printing secrets | `--file
|
|
33
|
-
| `kxm gate artifacts-exist` | Verify a non-empty workspace
|
|
65
|
+
| `kxm gate validate` | Parse JSON webhook workflow definitions without printing secrets | `--file <path>` |
|
|
66
|
+
| `kxm gate artifacts-exist` | Verify a non-empty file under workspace assets | `--path` (required) |
|
|
34
67
|
| `kxm gate degrade <runId> <stageId>` | Approve a configured lower peer quorum | `--requirement`, `--reason` |
|
|
35
|
-
| `kxm gate signal <runId> <signalKey> <status> <summary>` | Post a signed callback | `[evidence...]`, `--delivery-id` |
|
|
68
|
+
| `kxm gate signal <runId> <signalKey> <status> <summary>` | Post a signed callback | `[evidence...]`, `--delivery-id`, `--recovery-action retry\|fail\|cancel\|unblock` |
|
|
36
69
|
| `kxm gate github watch` | Poll required GitHub checks and signal | `--run-id`, `--stage-id`, `--signal-key`, `--repo`, `--pr`, `--required`, `--timeout-ms`, `--interval-ms`, `--delivery-id` |
|
|
37
70
|
|
|
71
|
+
`kxm gate validate` reads the hub's webhook definitions (`--file`, else
|
|
72
|
+
`KXM_WEBHOOK_WORKFLOWS_FILE` or `KXM_WEBHOOK_WORKFLOWS`), which are JSON. It
|
|
73
|
+
does not read project `.kxm/workflows/*.yaml`; validate those with
|
|
74
|
+
`kxm init --dry-run --json`.
|
|
75
|
+
|
|
76
|
+
`kxm gate signal` on a KXM run ID (`run_` plus 32 hex digits) goes to the
|
|
77
|
+
Runtime and passes `--recovery-action` through; on a hub webhook run it posts a
|
|
78
|
+
signed callback that needs `KXM_WORKFLOW_ID` and the definition's signal
|
|
79
|
+
secret. Reuse `--delivery-id` to retry one unchanged callback.
|
|
80
|
+
|
|
38
81
|
```bash
|
|
39
|
-
kxm
|
|
40
|
-
kxm
|
|
41
|
-
kxm workflow checkpoint run_12345 stage_abc passed "Implementation complete" --evidence '{"code_changes":"added feature"}' --json
|
|
42
|
-
kxm gate validate --file workflows/default.yaml --json
|
|
82
|
+
kxm gate validate --file workflows.json --json
|
|
83
|
+
kxm gate signal run_0123456789abcdef0123456789abcdef verify passed "operator verified" --recovery-action unblock --dry-run
|
|
43
84
|
```
|
|
44
85
|
|
|
45
86
|
Do not invent `gate list`, `gate run`, or `gate status`.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_CONTEXT_BUDGET_TOKENS,
|
|
3
3
|
MAX_CONTEXT_ITEMS,
|
|
4
|
+
contextItemCharacters,
|
|
4
5
|
estimateContextTokens,
|
|
5
6
|
parseContextItem,
|
|
6
7
|
parseContextRequest,
|
|
@@ -15,6 +16,13 @@ import {
|
|
|
15
16
|
type ContextSourceType,
|
|
16
17
|
} from "./context.ts";
|
|
17
18
|
import { ProtocolError } from "./protocol.ts";
|
|
19
|
+
import {
|
|
20
|
+
compareCodeUnitIds,
|
|
21
|
+
contextItemRelevanceText,
|
|
22
|
+
relevanceTokens,
|
|
23
|
+
roundRelevance,
|
|
24
|
+
scoreRelevance,
|
|
25
|
+
} from "./relevance.ts";
|
|
18
26
|
import type { SkillLifecycle } from "./skills.ts";
|
|
19
27
|
import type { JournalCategory, WorkflowJournalEntry } from "./workflow.ts";
|
|
20
28
|
import type { MemoryRecord } from "./memory.ts";
|
|
@@ -44,7 +52,7 @@ export const ROLE_POLICIES: readonly RoleContextPolicy[] = [
|
|
|
44
52
|
{
|
|
45
53
|
role: "repro",
|
|
46
54
|
label: "Reproduction specialist",
|
|
47
|
-
kinds: ["episode", "knowledge"],
|
|
55
|
+
kinds: ["episode", "knowledge", "evidence"],
|
|
48
56
|
journalCategories: ["error", "lesson", "observation", "contradiction"],
|
|
49
57
|
budgetTokens: 8_000,
|
|
50
58
|
},
|
|
@@ -65,7 +73,7 @@ export const ROLE_POLICIES: readonly RoleContextPolicy[] = [
|
|
|
65
73
|
{
|
|
66
74
|
role: "implementer",
|
|
67
75
|
label: "Implementer",
|
|
68
|
-
kinds: ["knowledge", "state", "skill", "episode"],
|
|
76
|
+
kinds: ["knowledge", "state", "skill", "episode", "evidence"],
|
|
69
77
|
journalCategories: ["plan", "decision", "lesson", "state-change"],
|
|
70
78
|
budgetTokens: 16_000,
|
|
71
79
|
},
|
|
@@ -97,8 +105,9 @@ export interface ArbiterOptions {
|
|
|
97
105
|
/** Pool item IDs that represent open contradictions; they are routed to the
|
|
98
106
|
* packet's contradictions section instead of their kind's section. */
|
|
99
107
|
contradictionIds?: string[];
|
|
100
|
-
/** Governed skill lifecycle
|
|
101
|
-
|
|
108
|
+
/** Governed skill lifecycle (or a pre-verified snapshot of one) to read and
|
|
109
|
+
* verify promoted skills by hash. */
|
|
110
|
+
skillLifecycle?: Pick<SkillLifecycle, "list" | "verify">;
|
|
102
111
|
}
|
|
103
112
|
|
|
104
113
|
export interface ArbiterOutcome {
|
|
@@ -114,12 +123,19 @@ export interface ArbiterOutcome {
|
|
|
114
123
|
candidateCount: number;
|
|
115
124
|
excludedSuperseded: number;
|
|
116
125
|
unresolvedGaps: string[];
|
|
126
|
+
/** Numbers only: distinct task tokens, eligible candidates sharing a task
|
|
127
|
+
* token, and each selected item's rounded BM25 score (index-aligned with
|
|
128
|
+
* selectedIds). */
|
|
129
|
+
relevance: { taskTokens: number; matchedCandidates: number; selected: number[] };
|
|
117
130
|
};
|
|
118
131
|
}
|
|
119
132
|
|
|
120
133
|
/** Deterministically assemble a role-aware context packet. Superseded and
|
|
121
134
|
* rejected records are excluded by default; cross-project content fails
|
|
122
|
-
* closed;
|
|
135
|
+
* closed; eligible candidates are ranked by contradiction, project-first,
|
|
136
|
+
* task match, role kind priority, BM25 task relevance, confidence,
|
|
137
|
+
* authority, recency (newest first), then id by code unit; the token budget
|
|
138
|
+
* is filled first-fit on the serialized selection. */
|
|
123
139
|
export function arbitrate(
|
|
124
140
|
requestInput: unknown,
|
|
125
141
|
pool: ContextItem[],
|
|
@@ -180,38 +196,62 @@ export function arbitrate(
|
|
|
180
196
|
return rank === undefined ? requestedKinds.length : rank;
|
|
181
197
|
};
|
|
182
198
|
|
|
183
|
-
|
|
199
|
+
// Eligibility: open contradictions always compete; everything else must be
|
|
200
|
+
// a requested kind and not an inert proposal (a non-current state or a
|
|
201
|
+
// proposed skill), so proposals never consume budget.
|
|
202
|
+
const allowedKinds = new Set<ContextItemKind>(requestedKinds);
|
|
203
|
+
const inertProposal = (item: ContextItem): boolean =>
|
|
204
|
+
(item.kind === "state" && item.status !== undefined && item.status !== "current")
|
|
205
|
+
|| (item.kind === "skill" && item.status === "proposed");
|
|
206
|
+
const eligible = candidates.filter((item) =>
|
|
207
|
+
contradictions.has(item.id) || (allowedKinds.has(item.kind) && !inertProposal(item)));
|
|
208
|
+
|
|
209
|
+
const scoreList = scoreRelevance(request.task, eligible.map(contextItemRelevanceText));
|
|
210
|
+
const scores = new Map<ContextItem, number>();
|
|
211
|
+
eligible.forEach((item, index) => scores.set(item, scoreList[index] ?? 0));
|
|
212
|
+
const scoreOf = (item: ContextItem): number => scores.get(item) ?? 0;
|
|
213
|
+
// Recency from the item's own timestamps; never reads the clock.
|
|
214
|
+
const when = (item: ContextItem): number => {
|
|
215
|
+
const parsed = Date.parse(item.observedAt ?? item.validFrom ?? "");
|
|
216
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const ordered = [...eligible].sort((left, right) =>
|
|
184
220
|
(contradictions.has(right.id) ? 1 : 0) - (contradictions.has(left.id) ? 1 : 0)
|
|
185
221
|
|| (left.project === request.project ? 0 : 1) - (right.project === request.project ? 0 : 1)
|
|
222
|
+
|| (scoreOf(right) > 0 ? 1 : 0) - (scoreOf(left) > 0 ? 1 : 0)
|
|
186
223
|
|| kindPreference(left) - kindPreference(right)
|
|
224
|
+
|| scoreOf(right) - scoreOf(left)
|
|
187
225
|
|| CONFIDENCE_RANK[right.confidence] - CONFIDENCE_RANK[left.confidence]
|
|
188
226
|
|| AUTHORITY_WEIGHT[right.authority] - AUTHORITY_WEIGHT[left.authority]
|
|
189
|
-
||
|
|
227
|
+
|| when(right) - when(left)
|
|
228
|
+
|| compareCodeUnitIds(left.id, right.id),
|
|
190
229
|
);
|
|
191
230
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|| contradictions.has(item.id);
|
|
195
|
-
|
|
231
|
+
// First-fit: an item that does not fit is deferred and smaller items keep
|
|
232
|
+
// filling the budget.
|
|
196
233
|
const selected: ContextItem[] = [];
|
|
197
234
|
const unresolvedGaps: string[] = [];
|
|
235
|
+
let characters = 0;
|
|
236
|
+
let deferredForBudget = 0;
|
|
198
237
|
for (const item of ordered) {
|
|
199
238
|
if (selected.length >= MAX_CONTEXT_ITEMS) {
|
|
200
239
|
unresolvedGaps.push("context item limit reached; refine the task or kinds");
|
|
201
240
|
break;
|
|
202
241
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
unresolvedGaps.push(`budget of ${budget} tokens cannot fit any selected context`);
|
|
208
|
-
break;
|
|
209
|
-
}
|
|
210
|
-
unresolvedGaps.push(`budget of ${budget} tokens reached; ${ordered.length - selected.length} candidates deferred`);
|
|
211
|
-
break;
|
|
242
|
+
const itemCharacters = contextItemCharacters(item);
|
|
243
|
+
if (Math.ceil((characters + itemCharacters) / 4) > budget) {
|
|
244
|
+
deferredForBudget += 1;
|
|
245
|
+
continue;
|
|
212
246
|
}
|
|
247
|
+
characters += itemCharacters;
|
|
213
248
|
selected.push(item);
|
|
214
249
|
}
|
|
250
|
+
if (deferredForBudget > 0) {
|
|
251
|
+
unresolvedGaps.push(selected.length === 0
|
|
252
|
+
? `budget of ${budget} tokens cannot fit any selected context`
|
|
253
|
+
: `budget of ${budget} tokens reached; ${deferredForBudget} candidates deferred`);
|
|
254
|
+
}
|
|
215
255
|
if (candidates.length === 0) {
|
|
216
256
|
unresolvedGaps.push("no context records exist for this project yet");
|
|
217
257
|
}
|
|
@@ -223,6 +263,7 @@ export function arbitrate(
|
|
|
223
263
|
workingState: options.workingState ?? {},
|
|
224
264
|
currentState: bySection("state").filter((item) => item.status === "current" || item.status === undefined),
|
|
225
265
|
knowledge: bySection("knowledge"),
|
|
266
|
+
evidence: bySection("evidence"),
|
|
226
267
|
episodes: bySection("episode"),
|
|
227
268
|
skills: bySection("skill").filter((item) => item.status !== "proposed"),
|
|
228
269
|
contradictions: selected.filter((item) => contradictions.has(item.id)),
|
|
@@ -249,6 +290,11 @@ export function arbitrate(
|
|
|
249
290
|
candidateCount: candidates.length,
|
|
250
291
|
excludedSuperseded,
|
|
251
292
|
unresolvedGaps,
|
|
293
|
+
relevance: {
|
|
294
|
+
taskTokens: new Set(relevanceTokens(request.task)).size,
|
|
295
|
+
matchedCandidates: scoreList.filter((score) => score > 0).length,
|
|
296
|
+
selected: selected.map((item) => roundRelevance(scoreOf(item))),
|
|
297
|
+
},
|
|
252
298
|
},
|
|
253
299
|
};
|
|
254
300
|
}
|
|
@@ -273,12 +319,11 @@ export function journalEntryToContextItem(entry: WorkflowJournalEntry, project:
|
|
|
273
319
|
},
|
|
274
320
|
authority: entry.category === "decision" || entry.category === "plan" ? "evidence" : "evidence",
|
|
275
321
|
confidence: entry.severity === "error" ? "probable" : "probable",
|
|
276
|
-
|
|
322
|
+
observedAt: entry.createdAt,
|
|
277
323
|
evidenceRefs: entry.evidence
|
|
278
324
|
.filter((ref) => ref.length > 0 && ref.length <= 200)
|
|
279
325
|
.slice(0, 16),
|
|
280
326
|
};
|
|
281
|
-
if (entry.stageId !== undefined) item.observedAt = entry.createdAt;
|
|
282
327
|
if (kind === "skill") item.status = "proposed";
|
|
283
328
|
return parseContextItem(item);
|
|
284
329
|
}
|
|
@@ -145,7 +145,7 @@ _kxm() {
|
|
|
145
145
|
'peer:Peer agent messaging and coordination'
|
|
146
146
|
'workflow:Start and inspect workflow runs'
|
|
147
147
|
'gate:Validate definitions and operate evidence gates'
|
|
148
|
-
'improve:Propose
|
|
148
|
+
'improve:Propose coded-repeat candidates from routing records'
|
|
149
149
|
'context:KXM context operating-system queries'
|
|
150
150
|
'skills:Governed skill candidate lifecycle'
|
|
151
151
|
'memory:Harness-agnostic Git memory operations'
|