@kurrent/kcap 1.3.0-beta.6 → 1.3.0-beta.7
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/bin/refresh.js +26 -144
- package/bin/resolve.js +2 -7
- package/kcap/.claude-plugin/plugin.json +1 -1
- package/kcap/README.md +1 -0
- package/kcap/hooks/hooks.json +10 -0
- package/kcap/skills/agent-flows/SKILL.md +36 -25
- package/kcap/skills/eval-watch/SKILL.md +94 -131
- package/kcap/skills/review-flows/SKILL.md +9 -4
- package/kcap/skills/start-agents/SKILL.md +4 -0
- package/package.json +9 -9
- package/kcap/skills/suggest-review-flow/SKILL.md +0 -94
package/bin/refresh.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// Refreshes kcap's user-scope coding-agent installs
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// Refreshes kcap's user-scope coding-agent installs after an install or upgrade, by running
|
|
2
|
+
// `kcap refresh` — the native binary owns the refresh list and the Claude plugin's .mcp.json patch,
|
|
3
|
+
// so every installer (npm, the install scripts, a script install's `kcap update`) runs the same one.
|
|
4
4
|
//
|
|
5
5
|
// Shared by:
|
|
6
6
|
// - postinstall.js — runs after `npm install -g @kurrent/kcap` (incl. upgrades),
|
|
@@ -10,152 +10,34 @@
|
|
|
10
10
|
//
|
|
11
11
|
// This file must never require kcap.js: during `kcap update`, runUpdate executes
|
|
12
12
|
// before kcap.js's final module.exports assignment, so it would observe partial
|
|
13
|
-
// exports.
|
|
13
|
+
// exports.
|
|
14
14
|
|
|
15
15
|
const { spawnSync } = require("child_process");
|
|
16
|
-
const path = require("path");
|
|
17
|
-
const fs = require("fs");
|
|
18
16
|
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
// opted in (marker file present OR pre-marker install detected). A vendor entry
|
|
22
|
-
// also refreshes the shared ~/.agents/skills tree, but only tops up one that is
|
|
23
|
-
// already there: `plugin remove --skills` must survive an upgrade. The daemon
|
|
24
|
-
// entry needs no marker: it acts only on service units that are already installed.
|
|
25
|
-
const REFRESHES = [
|
|
26
|
-
["plugin", "install", "--skills", "--if-installed"],
|
|
27
|
-
["plugin", "install", "--codex", "--if-installed"],
|
|
28
|
-
["plugin", "install", "--cursor", "--if-installed"],
|
|
29
|
-
["plugin", "install", "--copilot", "--if-installed"],
|
|
30
|
-
["plugin", "install", "--pi", "--if-installed"], // Pi extension (~/.pi/agent/extensions/kcap.ts)
|
|
31
|
-
["plugin", "install", "--opencode", "--if-installed"], // OpenCode plugin (~/.config/opencode/plugins/kcap.ts)
|
|
32
|
-
["plugin", "install", "--gemini", "--if-installed"], // Gemini hooks/MCP/instructions (~/.gemini)
|
|
33
|
-
["plugin", "install", "--kiro", "--if-installed"], // Kiro agent hooks (~/.kiro/agents/kcap.json)
|
|
34
|
-
["plugin", "install", "--antigravity", "--if-installed"], // Antigravity hooks (~/.gemini/config/plugins/kcap)
|
|
35
|
-
["plugin", "install", "--if-installed"], // Claude
|
|
36
|
-
["daemon", "service", "refresh"],
|
|
37
|
-
];
|
|
17
|
+
// Above the binary's own worst case: eleven steps, each bounded at 60s.
|
|
18
|
+
const REFRESH_TIMEOUT_MS = 15 * 60_000;
|
|
38
19
|
|
|
39
|
-
// Runs
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
function runRefreshes(launcherPath) {
|
|
44
|
-
// Point the shipped Claude plugin's MCP entries at the native binary. Runs
|
|
45
|
-
// here because runRefreshes fires at exactly the two moments the plugin dir
|
|
46
|
-
// has just been (re)written by npm: postinstall and `kcap update`.
|
|
47
|
-
patchPluginMcpConfig(launcherPath);
|
|
48
|
-
|
|
49
|
-
for (const argv of REFRESHES) {
|
|
50
|
-
try {
|
|
51
|
-
spawnSync(process.execPath, [launcherPath, ...argv], {
|
|
52
|
-
stdio: "ignore",
|
|
53
|
-
env: process.env,
|
|
54
|
-
// Hard ceiling so a stalled child can never hang the caller.
|
|
55
|
-
timeout: 60_000,
|
|
56
|
-
killSignal: "SIGKILL",
|
|
57
|
-
windowsHide: true,
|
|
58
|
-
});
|
|
59
|
-
} catch {
|
|
60
|
-
// Never fail the caller.
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// ── Claude plugin .mcp.json patch ───────────────────────────────────────────
|
|
66
|
-
//
|
|
67
|
-
// The plugin ships `"command": "kcap"`, which resolves to the node wrapper —
|
|
68
|
-
// one resident Node runtime per MCP server per open Claude session (~25 MB
|
|
69
|
-
// idle each). Rewriting the command to the resolved native binary makes Claude
|
|
70
|
-
// spawn the binary directly. Best-effort: on any failure the shipped value
|
|
71
|
-
// stays in place, which still works via the wrapper.
|
|
72
|
-
|
|
73
|
-
// The servers shipped in the plugin's .mcp.json, keyed by canonical
|
|
74
|
-
// `["mcp", <suffix>]` args. Only these exact name/args pairs are patched —
|
|
75
|
-
// anything else in the file is preserved verbatim.
|
|
76
|
-
const PLUGIN_MCP_SERVERS = {
|
|
77
|
-
"kcap-review": "review",
|
|
78
|
-
"kcap-sessions": "sessions",
|
|
79
|
-
"kcap-flows": "flows",
|
|
80
|
-
"kcap-memory": "memory",
|
|
81
|
-
"kcap-workitems": "workitems",
|
|
82
|
-
"kcap-plans": "plans",
|
|
83
|
-
"kcap-artefacts": "artefacts",
|
|
84
|
-
"kcap-analytics": "analytics",
|
|
85
|
-
"kcap-knowledge": "knowledge",
|
|
86
|
-
"kcap-handoff": "handoff",
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
// A command this patcher may rewrite: the shipped literal "kcap", or an
|
|
90
|
-
// absolute path whose basename is the kcap binary (a previous patch that has
|
|
91
|
-
// gone stale after an npm re-layout). Handles both path flavors so a stale
|
|
92
|
-
// Windows path is still recognized. Anything else is a customization → keep.
|
|
93
|
-
function isPatchableKcapCommand(command) {
|
|
94
|
-
if (command === "kcap") return true;
|
|
95
|
-
if (typeof command !== "string") return false;
|
|
96
|
-
if (!path.posix.isAbsolute(command) && !path.win32.isAbsolute(command)) return false;
|
|
97
|
-
const base = command.split(/[\\/]/).pop().toLowerCase();
|
|
98
|
-
return base === "kcap" || base === "kcap.exe";
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Pure: rewrites in place the canonical plugin entries of `cfg` whose command
|
|
102
|
-
// is patchable, returning whether anything changed. Throws on a shape that
|
|
103
|
-
// isn't the plugin config (caller turns that into the single warning).
|
|
104
|
-
function patchPluginMcpServers(cfg, binaryPath) {
|
|
105
|
-
if (!cfg || typeof cfg !== "object" || Array.isArray(cfg)) {
|
|
106
|
-
throw new Error("config is not an object");
|
|
107
|
-
}
|
|
108
|
-
const servers = cfg.mcpServers;
|
|
109
|
-
if (!servers || typeof servers !== "object" || Array.isArray(servers)) {
|
|
110
|
-
throw new Error("mcpServers is not an object");
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
let changed = false;
|
|
114
|
-
for (const [name, suffix] of Object.entries(PLUGIN_MCP_SERVERS)) {
|
|
115
|
-
const entry = servers[name];
|
|
116
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
117
|
-
if (!Array.isArray(entry.args) || entry.args.length !== 2 ||
|
|
118
|
-
entry.args[0] !== "mcp" || entry.args[1] !== suffix) continue; // customized args → keep
|
|
119
|
-
if (!isPatchableKcapCommand(entry.command)) continue; // customized command → keep
|
|
120
|
-
if (entry.command === binaryPath) continue; // already current
|
|
121
|
-
entry.command = binaryPath;
|
|
122
|
-
changed = true;
|
|
123
|
-
}
|
|
124
|
-
return changed;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Rewrites the plugin's shipped .mcp.json (a sibling `kcap/` dir of the
|
|
128
|
-
// launcher's `bin/`) so Claude spawns the native binary directly. Validates
|
|
129
|
-
// before writing, writes a sibling temp file, then renames atomically — the
|
|
130
|
-
// original survives any pre-rename failure. Never throws; on failure it emits
|
|
131
|
-
// ONE concise warning and leaves the shipped `"command": "kcap"` in place.
|
|
132
|
-
// `binaryPath` is a test seam; real callers let it resolve.
|
|
133
|
-
function patchPluginMcpConfig(launcherPath, binaryPath) {
|
|
134
|
-
let mcpJsonPath;
|
|
20
|
+
// Runs `kcap refresh` through the given launcher (an absolute path to kcap.js), so the NEW
|
|
21
|
+
// launcher and the NEW binary run it after an upgrade. Never throws and never fails the caller:
|
|
22
|
+
// a failed refresh must never break `npm install` or report `kcap update` as failed. Its stderr
|
|
23
|
+
// (which steps failed, a plugin patch that could not be written) is passed on through `warn`.
|
|
24
|
+
function runRefreshes(launcherPath, warn = console.warn) {
|
|
135
25
|
try {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
try { fs.unlinkSync(tmp); } catch {}
|
|
151
|
-
throw e;
|
|
152
|
-
}
|
|
153
|
-
} catch (e) {
|
|
154
|
-
console.warn(
|
|
155
|
-
`kcap: could not point the Claude plugin MCP entries at the native binary` +
|
|
156
|
-
` (${e && e.message ? e.message : e}); they will keep launching via the node wrapper.`,
|
|
157
|
-
);
|
|
26
|
+
const result = spawnSync(process.execPath, [launcherPath, "refresh"], {
|
|
27
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
28
|
+
encoding: "utf8",
|
|
29
|
+
env: process.env,
|
|
30
|
+
timeout: REFRESH_TIMEOUT_MS,
|
|
31
|
+
killSignal: "SIGKILL",
|
|
32
|
+
windowsHide: true,
|
|
33
|
+
});
|
|
34
|
+
const stderr = (result.stderr || "").trim();
|
|
35
|
+
if (stderr) warn(stderr);
|
|
36
|
+
if (result.status !== 0)
|
|
37
|
+
warn("kcap: some agent integrations were not refreshed; run `kcap refresh` to retry.");
|
|
38
|
+
} catch {
|
|
39
|
+
// Never fail the caller.
|
|
158
40
|
}
|
|
159
41
|
}
|
|
160
42
|
|
|
161
|
-
module.exports = { runRefreshes
|
|
43
|
+
module.exports = { runRefreshes };
|
package/bin/resolve.js
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
// Side-effect-free platform/native-binary resolution
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// This lives in its OWN module — refresh.js must never require kcap.js: during
|
|
5
|
-
// `kcap update`, runUpdate executes BEFORE kcap.js's final module.exports
|
|
6
|
-
// assignment, so a refresh.js → kcap.js require would observe partial exports
|
|
7
|
-
// exactly on that path. Requiring this module has no side effects.
|
|
1
|
+
// Side-effect-free platform/native-binary resolution for kcap.js (the launcher).
|
|
2
|
+
// Requiring this module has no side effects.
|
|
8
3
|
|
|
9
4
|
const path = require("path");
|
|
10
5
|
const fs = require("fs");
|
package/kcap/README.md
CHANGED
|
@@ -20,6 +20,7 @@ Search and recall past Kurrent Capacitor sessions from inside the agent.
|
|
|
20
20
|
| `get_session_transcript` | Speaker-tagged transcript window, with `around_event` drill-in for search hits |
|
|
21
21
|
| `list_repo_plans` | List a repository's declared plans you can see, most recently touched first |
|
|
22
22
|
| `get_declared_plans` | A plan's documents and full task list, by `plan_id` or `session_id` |
|
|
23
|
+
| `get_session_evals` | Eval state and scores for up to 25 sessions by id; works on every plan |
|
|
23
24
|
|
|
24
25
|
Repo-aware: it resolves the cwd to a repo hash at startup, so `search_sessions` defaults to *this* repo.
|
|
25
26
|
|
package/kcap/hooks/hooks.json
CHANGED
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: agent-flows
|
|
3
3
|
description: >-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
work directly instead. To start a hosted agent that works on its own, use
|
|
17
|
-
`start-agents`.
|
|
4
|
+
Use this skill to drive a structured agent *flow*: a separate hosted
|
|
5
|
+
participant agent runs a definition from the server's flow catalogue and
|
|
6
|
+
iterates with you until sign-off. Use it when the user names a flow or
|
|
7
|
+
definition id ("run the code-review flow", "start a flow", "use flow
|
|
8
|
+
definition X"), when the user accepts a flow you offered, or when you are
|
|
9
|
+
about to offer one listed under "Flows you may offer" in your session
|
|
10
|
+
context because its when-to-use applies. Before starting a flow, call
|
|
11
|
+
get_flow_definition and follow its guide. Do NOT use this skill (and do NOT
|
|
12
|
+
call the flows MCP tools) for an ordinary request such as "review my PR",
|
|
13
|
+
"do X for me", or "check this over" where the user wants you to do the work
|
|
14
|
+
yourself — do it directly instead. To start a hosted agent that works on its
|
|
15
|
+
own, use `start-agents`.
|
|
18
16
|
---
|
|
19
17
|
|
|
20
18
|
# Agent Flows
|
|
21
19
|
|
|
22
|
-
Use the `kcap mcp flows` MCP tools (`list_flow_definitions`, `start_flow`, `send_to_participant`, `get_flow_status`, `close_flow`) to run a structured agent **flow**: your work is handed to a **separate, hosted participant agent** driven by a flow definition from the server's catalog, which returns a result (kind `findings` with the participant's result text, or `clean`); you address a `findings` result and keep iterating until the clean signal. This is a deliberate, heavier workflow — use it
|
|
20
|
+
Use the `kcap mcp flows` MCP tools (`list_flow_definitions`, `get_flow_definition`, `start_flow`, `send_to_participant`, `get_flow_status`, `close_flow`) to run a structured agent **flow**: your work is handed to a **separate, hosted participant agent** driven by a flow definition from the server's catalog, which returns a result (kind `findings` with the participant's result text, or `clean`); you address a `findings` result and keep iterating until the clean signal. This is a deliberate, heavier workflow — use it when the user asks for a flow or accepts one you offered, never on your own initiative.
|
|
23
21
|
|
|
24
22
|
## Long rounds are normal
|
|
25
23
|
|
|
@@ -39,15 +37,14 @@ and end the reviewer turn. The hosted-reviewer contract wins over driver-looking
|
|
|
39
37
|
|
|
40
38
|
These tools do **not** perform the work themselves — they hand it off to a separate hosted participant agent running a named flow definition. If the user simply asked *you* to do something in a normal session — e.g. "review my PR", "review this diff", "check this spec", "do X" — just do it yourself and report the result directly. Do **NOT** call `start_flow` / `send_to_participant` for an ordinary request; that would spin up a hosted agent the user did not ask for.
|
|
41
39
|
|
|
42
|
-
Only start a flow when the user explicitly asks for
|
|
40
|
+
Only start a flow when the user explicitly asks for one — e.g. "start a flow", "run the code-review flow", "use flow definition X", or "re-review after I address the findings" via a flow — or accepts a flow you offered. Offer a flow only when your session context lists it under **Flows you may offer** and its when-to-use applies to what just happened; ask, and never start it before the user says yes. Skip the offer when the user asked you to do the work yourself, or while you are mid-task.
|
|
43
41
|
|
|
44
42
|
## Choosing the flow definition
|
|
45
43
|
|
|
46
|
-
Once the user has
|
|
44
|
+
Once the user has asked for a flow or accepted one you offered (see above), pick the `definition_id`:
|
|
47
45
|
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
- Anything else → the definition id the user named, or one from `list_flow_definitions` (read-only), which lists every definition this server can start — operator-published ones included — with its version, description, participant roles and their authored vendor and model, and whether it is single- or multi-participant. Call it whenever the user has not named a definition, or named one you have not seen listed: a definition it does not list is disabled, deleted or unknown, and `start_flow` will refuse it. If several fit, ask the user rather than guessing. A server that answers that it cannot list definitions only predates the tool — the two built-ins and any id the user names still work.
|
|
46
|
+
- The flow the user named, or the one you offered and they accepted.
|
|
47
|
+
- If the user has not named one → choose from `list_flow_definitions` (read-only), which lists every definition this server can start — operator-published ones included — with its version, description, participant roles and their authored vendor and model, and whether it is single- or multi-participant. Call it whenever the user has not named a definition, or named one you have not seen listed: a definition it does not list is disabled, deleted or unknown, and `start_flow` will refuse it. If several fit, ask the user rather than guessing. A server that answers that it cannot list definitions only predates the tool — the two built-ins and any id the user names still work.
|
|
51
48
|
|
|
52
49
|
For the reserved `spec-review` and `code-review` aliases, reviewer-vendor language is role-bound:
|
|
53
50
|
pass the one vendor explicitly named as the reviewer, ignore driver-harness mentions, honor
|
|
@@ -88,6 +85,10 @@ vendor supports this: the daemon must advertise a runtime model resolver for the
|
|
|
88
85
|
(Claude and Codex today; other vendors keep vendor-only overrides with no model choice) or the
|
|
89
86
|
server rejects the override outright.
|
|
90
87
|
|
|
88
|
+
## Read the flow's guide first
|
|
89
|
+
|
|
90
|
+
Before a catalogue start (`definition_id`), call `get_flow_definition(definition_id)`. The guide is written by whoever published the flow: what to put in `context`, which target to name, how to iterate on its results and when to close. Where it differs from the generic rules below, follow the guide. A server that does not publish guides says so; then work from the definition's description and the rules below. A flow started with an inline `definition_yaml` has no catalogue id and no guide: drive it by the generic rules and its own YAML.
|
|
91
|
+
|
|
91
92
|
## Composing a dynamic flow
|
|
92
93
|
|
|
93
94
|
If nothing `list_flow_definitions` shows fits — no `definition_id` covers the roles or workflow you need — compose one inline instead: pass `definition_yaml` to `start_flow` in place of `definition_id`. Provide exactly one of the two, never both. (`start_review_flow` / `submit_review_round` stay catalog-only — this only applies to the generic `start_flow`.)
|
|
@@ -147,7 +148,7 @@ After applying the role-surface safety gate, if `start_flow` / `send_to_particip
|
|
|
147
148
|
5. **If participant output is unclear or requires user input**, pause and ask the user before proceeding.
|
|
148
149
|
6. **Never start a nested flow.** If you are the hosted participant (see above), do not call these tools yourself.
|
|
149
150
|
7. **Address each role independently.** A flow definition declares one or more participant roles in its `participants` map (single-participant definitions use `reviewer`). A multi-participant `start_flow` returns no round — nothing has launched yet. Call `send_to_participant(flow_run_id, participant=<role>, message=…)` naming the role you want to address; its first message launches that role's agent lazily. Only one round is in flight per role at a time — sending to a role that's still working on a round gets a `409` naming the busy round — but every OTHER role stays addressable in the meantime. Sending an unknown role is rejected by the server, which names the valid roles in its error.
|
|
150
|
-
8. **
|
|
151
|
+
8. **Ask the participant only for what the flow's guide allows.** If the guide says CI covers tests, do not ask the participant to run them; participant feedback is on what the flow exists to judge.
|
|
151
152
|
9. **State where your changes live.** The participant's worktree is mirrored from **this session's project directory**, not from the directory you are working in, and no tool parameter can redirect it. So if you changed directory, are a subagent in another checkout, or the changeset lives in another worktree/repo/machine, the participant will NOT see it: say so in `context`/`message`, give it an explicit commit range (never `git diff origin/main...HEAD`), and inline the diffs — or pass `mode: "context-only"` to make your context the sole source of truth. The participant flags referenced changes it cannot find; incomplete context wastes a full round.
|
|
152
153
|
|
|
153
154
|
## Pending messages
|
|
@@ -170,10 +171,17 @@ The server enforces per-run budgets; watch for these in tool error responses:
|
|
|
170
171
|
|
|
171
172
|
## Workflow
|
|
172
173
|
|
|
174
|
+
A catalogue flow (`definition_id`) starts with its guide; an inline `definition_yaml` flow skips this step:
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
get_flow_definition(definition_id)
|
|
178
|
+
→ read the driver guide; prepare the context it asks for
|
|
179
|
+
```
|
|
180
|
+
|
|
173
181
|
Single-participant definitions start eagerly — round 1 runs as part of `start_flow`:
|
|
174
182
|
|
|
175
183
|
```
|
|
176
|
-
start_flow(definition_id, target_kind, target_ref, target_title, context)
|
|
184
|
+
start_flow(definition_id, target_kind, target_ref, target_title, session_title, context)
|
|
177
185
|
→ participant returns a result: kind findings (with the result text) | kind clean
|
|
178
186
|
|
|
179
187
|
if clean:
|
|
@@ -192,7 +200,7 @@ if findings:
|
|
|
192
200
|
Multi-participant definitions start round-less — you address each role yourself, and the run is clean only in aggregate:
|
|
193
201
|
|
|
194
202
|
```
|
|
195
|
-
start_flow(definition_id, target_kind, target_ref, target_title, context)
|
|
203
|
+
start_flow(definition_id, target_kind, target_ref, target_title, session_title, context)
|
|
196
204
|
→ no round yet — roles have not launched
|
|
197
205
|
|
|
198
206
|
send_to_participant(flow_run_id, participant="reviewer", message=…)
|
|
@@ -218,7 +226,8 @@ report completion to user
|
|
|
218
226
|
| Tool | Required args | Optional args | When to call |
|
|
219
227
|
|---|---|---|---|
|
|
220
228
|
| `list_flow_definitions` | — | — | Before `start_flow`, whenever the user has not named a definition or named one you have not seen listed. Read-only: returns each runnable definition's id, version, description, whether it is single- or multi-participant, and its participants' role, authored vendor and model. A `server_catching_up` error is retryable — do not read it as an empty catalog. |
|
|
221
|
-
| `
|
|
229
|
+
| `get_flow_definition` | `definition_id` | — | Before every catalogue (`definition_id`) `start_flow`. Read-only: returns the definition's participants and when to use it, then its authored driver guide (what to submit, how to iterate, when to close). An unknown, disabled or deleted id is an error; an older server reports that it publishes no guides. |
|
|
230
|
+
| `start_flow` | Exactly one of `definition_id` (catalog id, e.g. `spec-review`, `code-review`, or a custom catalog id) or `definition_yaml` (inline dynamic definition — see "Composing a dynamic flow"); plus `target_kind` (what is being worked on: `spec`, `code`, `pr`, `branch`, `file`, etc.), `target_ref` (a path, branch name, or PR URL/number that identifies the target), `target_title` (short human-readable title), `session_title` (the participant session's title: a short phrase naming this piece of work, specific enough to tell it apart from other sessions — it replaces the definition's generic opening instruction as the name), `context` (background context: what to focus on, constraints, definition of done) | `vendor` (reserved aliases only — explicit reviewer vendor; omit to use the definition's authored vendor, or your saved `flows.reviewer_vendor` preference if it declares none), `model` (reserved aliases only — explicit reviewer model override; REQUIRES `vendor`, rejected on dynamic/multi-participant starts), `instructions`, `mode` (`context-only` — optional; by default the participant's worktree is mirrored from THIS SESSION's project directory, not from the directory you are working in. Pass `context-only` to opt out and treat the submitted context as authoritative) | Once, at the start of a flow task. |
|
|
222
231
|
| `send_to_participant` | `flow_run_id`, `participant` (role name declared in the flow definition's `participants` map; single-participant definitions use `reviewer` — an unknown role is rejected, naming the valid ones), `message` | `instructions`, `async` (defaults to `true`) | After addressing a non-clean result for that role, or to launch a role for the first time. Pass the same `flow_run_id`, the role's name, and the updated message. |
|
|
223
232
|
| `get_flow_status` | — | `flow_run_id` (omit to read the newest open flow this session started, or on a harness without a session identity the newest one started from this workspace; several open flows are listed instead), `session_id` (look up another session's flows; defaults to this session), `wait` (`true`/`false`, defaults to `false`) — when `true`, blocks until the round is terminal or roughly 3.5 minutes pass, instead of returning the current snapshot immediately | Poll or check the current status of a flow run (running, waiting, completed, failed). Use `wait: true` to ride out a long round instead of polling repeatedly yourself, and omit `flow_run_id` to recover a flow whose id you never received or lost. |
|
|
224
233
|
| `close_flow` | `flow_run_id` | — | Only after the definition's clean signal — or when abandoning the task early; the run otherwise stays open until closed. |
|
|
@@ -226,13 +235,14 @@ report completion to user
|
|
|
226
235
|
## Example (custom definition)
|
|
227
236
|
|
|
228
237
|
```
|
|
229
|
-
# Step 1 — start (all
|
|
238
|
+
# Step 1 — start (all six args required; the participant sees a mirror of THIS SESSION's
|
|
230
239
|
# project directory, not of the directory you are working in — pass mode="context-only" to opt out)
|
|
231
240
|
start_flow(
|
|
232
241
|
definition_id="code-review",
|
|
233
242
|
target_kind="branch",
|
|
234
243
|
target_ref="feature/add-null-check",
|
|
235
244
|
target_title="Add null check on user input",
|
|
245
|
+
session_title="Review the null check on user input",
|
|
236
246
|
context="Review the diff on this branch for correctness and adherence to project conventions."
|
|
237
247
|
)
|
|
238
248
|
# → returns flow_run_id, e.g. "flow_abc123"
|
|
@@ -261,6 +271,7 @@ start_flow(
|
|
|
261
271
|
target_kind="branch",
|
|
262
272
|
target_ref="feature/add-null-check",
|
|
263
273
|
target_title="Add null check on user input",
|
|
274
|
+
session_title="Review and test the null check on user input",
|
|
264
275
|
context="Review the diff on this branch and write/run tests for the new code path."
|
|
265
276
|
)
|
|
266
277
|
# → returns flow_run_id, e.g. "flow_xyz789"; no round in the response
|
|
@@ -4,38 +4,31 @@ description: >-
|
|
|
4
4
|
Follow a kcap import that setup just started and the evals landing on it —
|
|
5
5
|
"Follow my kcap import" (the prompt `kcap setup` hands to your agent), "watch my
|
|
6
6
|
import", "how is my import going", "are my evals done yet". Reads the handoff file
|
|
7
|
-
setup wrote, polls
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
skill.
|
|
7
|
+
setup wrote, polls the eval state of exactly the sessions that import created,
|
|
8
|
+
waits for the sessions that imported while the user watched to be evaluated,
|
|
9
|
+
summarizes their evals, links to the results and offers the guided tour. Works on
|
|
10
|
+
every plan. Not for browsing evals in general — that is the guided-tour skill.
|
|
12
11
|
---
|
|
13
12
|
|
|
14
13
|
# Eval watch
|
|
15
14
|
|
|
16
|
-
You follow ONE import: the sessions listed in a handoff file `kcap setup` wrote. Every
|
|
17
|
-
|
|
18
|
-
an
|
|
19
|
-
|
|
15
|
+
You follow ONE import: the sessions listed in a handoff file `kcap setup` wrote. Every lookup you
|
|
16
|
+
make names only those sessions — never a repo-wide or tenant-wide read. If a response ever carries
|
|
17
|
+
an entry for a session id outside the cohort, discard it: never count it, link it, or mention it.
|
|
18
|
+
|
|
19
|
+
Eval state comes from `get_session_evals` in the `kcap-sessions` MCP — never from the
|
|
20
|
+
`kcap-analytics` MCP, which is a paid feature the workspace may not have.
|
|
20
21
|
|
|
21
22
|
## The safety rule — read this first
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
Two grammars gate everything below:
|
|
24
25
|
- **Run id** (a `(run: <id>)` token, and the file's own `run_id`): `^[0-9a-f]{32}$`.
|
|
25
|
-
- **Session id** (`session_ids`, `foreground_succeeded_ids`, and any id you
|
|
26
|
-
`^[A-Za-z0-9_-]{1,128}$`.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
The `kcap-analytics` MCP takes raw SQL text with no parameter binding, so the session-id grammar is
|
|
32
|
-
the SQL-safety boundary, not just a format check. The class excludes quote, backslash, whitespace
|
|
33
|
-
and `;`, so a value that matches it can never close a string literal or open a new statement — a
|
|
34
|
-
matching id is emitted as a single-quoted literal (`'<id>'`) with **no escaping**, because none is
|
|
35
|
-
needed and none should be attempted. A run of hyphens such as `--` matches the grammar and is safe
|
|
36
|
-
to emit this way: inside a quoted literal it is data, not a SQL comment. An id that fails either
|
|
37
|
-
grammar is **never** placed in SQL, a path, or a link — reject it and move on (section 2 below says
|
|
38
|
-
what each layer's rejection does); never sanitize or escape an id into something that would pass.
|
|
26
|
+
- **Session id** (`session_ids`, `foreground_succeeded_ids`, and any id you pass to a tool or put
|
|
27
|
+
in a link): `^[A-Za-z0-9_-]{1,128}$`.
|
|
28
|
+
|
|
29
|
+
An id that fails its grammar is **never** placed in a tool call, a path, or a link — reject it and
|
|
30
|
+
move on (section 2 below says what each layer's rejection does); never sanitize or escape an id
|
|
31
|
+
into something that would pass.
|
|
39
32
|
|
|
40
33
|
## 1. Find the run
|
|
41
34
|
|
|
@@ -44,12 +37,12 @@ what each layer's rejection does); never sanitize or escape an id into something
|
|
|
44
37
|
it does match, the run is bound: read ONLY `<config>/import-handoff-<id>.json`, where `<config>`
|
|
45
38
|
is `$KCAP_CONFIG_DIR` when set, else `~/.config/kcap`, and check it against every Layer A rule in
|
|
46
39
|
section 2, plus one more: its `run_id` field must equal `<id>` exactly. Missing, unreadable, or
|
|
47
|
-
failing any of those checks → say so and CLOSE (section 7) with no
|
|
40
|
+
failing any of those checks → say so and CLOSE (section 7) with no lookup. **Never fall through to
|
|
48
41
|
another run's file** — a different run's cohort does not belong to the run the user asked for.
|
|
49
42
|
- Otherwise list `<config>/import-handoff-*.json`, keep the locator-valid ones (section 2) that are
|
|
50
|
-
watchable (`handoff_offered` true, or `handoff_suppressed` is `
|
|
51
|
-
`no_agent_detected`), pick the newest `written_at`, and say which others you passed over.
|
|
52
|
-
- Nothing qualifies → say you found no import to follow and CLOSE with no
|
|
43
|
+
watchable (`handoff_offered` true, or `handoff_suppressed` is `analytics_not_in_plan`,
|
|
44
|
+
`skill_not_installed` or `no_agent_detected`), pick the newest `written_at`, and say which others you passed over.
|
|
45
|
+
- Nothing qualifies → say you found no import to follow and CLOSE with no lookup.
|
|
53
46
|
|
|
54
47
|
## 2. Validate the file — three layers
|
|
55
48
|
|
|
@@ -57,24 +50,25 @@ A failure at a lower layer never re-opens the file for a higher one.
|
|
|
57
50
|
|
|
58
51
|
**Layer A** (may this file be selected at all): JSON parses; `schema_version` is 1; `run_id` matches
|
|
59
52
|
`^[0-9a-f]{32}$`; `written_at` parses as ISO-8601 and is within the last 24 hours; `handoff_offered`
|
|
60
|
-
is a boolean. Fail → not selectable; try the next candidate file, or close with no
|
|
53
|
+
is a boolean. Fail → not selectable; try the next candidate file, or close with no lookup if none
|
|
61
54
|
remain.
|
|
62
55
|
|
|
63
56
|
**Layer B** (may its ids drive data): `cohort` ∈ {exact, partial_exact, unknown}; `background` ∈
|
|
64
57
|
{not_needed, running, exited_zero, failed}; `foreground_certainty` ∈ {complete, incomplete};
|
|
65
58
|
`handoff_suppressed` is null or one of import_failed, no_new_sessions, nothing_landed,
|
|
66
|
-
analytics_not_in_plan, skill_not_installed, no_agent_detected
|
|
59
|
+
analytics_not_in_plan, skill_not_installed, no_agent_detected (older setups write
|
|
60
|
+
`analytics_not_in_plan`); every entry of `session_ids` and
|
|
67
61
|
`foreground_succeeded_ids` matches `^[A-Za-z0-9_-]{1,128}$`; `unattributed_on_disk` is a
|
|
68
62
|
non-negative integer. Fail → **no data**: the file stays selected, but say the record is unreadable
|
|
69
|
-
and CLOSE with links only (section 7), no
|
|
63
|
+
and CLOSE with links only (section 7), no lookup.
|
|
70
64
|
|
|
71
65
|
**Layer C** (may it supply links): `server_url` starts with `http://` or `https://`. Fail → no
|
|
72
|
-
file-sourced links (fall back to `kcap whoami` per section 7) and no
|
|
66
|
+
file-sourced links (fall back to `kcap whoami` per section 7) and no lookup — an unverifiable
|
|
73
67
|
`server_url` also means the server-binding check in section 4 cannot run. `background_log` and
|
|
74
68
|
`profile` are shown as plain text — never as a link or a command to run — only when they contain no
|
|
75
69
|
control characters and are under 512 characters; otherwise omit them.
|
|
76
70
|
|
|
77
|
-
Never splice an unvalidated value into
|
|
71
|
+
Never splice an unvalidated value into a tool call, a path, or a link.
|
|
78
72
|
|
|
79
73
|
## 3. No-handoff files
|
|
80
74
|
|
|
@@ -82,144 +76,113 @@ If `handoff_offered` is false, branch on `handoff_suppressed` and CLOSE:
|
|
|
82
76
|
- `no_new_sessions` → "nothing to watch — that import found no new sessions".
|
|
83
77
|
- `nothing_landed` → "the sessions that import selected were skipped at import time"; point at
|
|
84
78
|
`kcap import --all` for per-session reasons; no retry.
|
|
85
|
-
- `analytics_not_in_plan` → the plan sentence (section 6); the import ran; no retry.
|
|
86
79
|
- `import_failed` → "that import did not get running"; name `kcap import --all --yes` and the
|
|
87
80
|
`background_log` when displayable.
|
|
88
|
-
- `skill_not_installed` / `no_agent_detected` → the import ran and you
|
|
89
|
-
now: continue as if offered, watching the file's cohort as usual (sections 4–5).
|
|
81
|
+
- `analytics_not_in_plan` / `skill_not_installed` / `no_agent_detected` → the import ran and you
|
|
82
|
+
can follow it now: continue as if offered, watching the file's cohort as usual (sections 4–5).
|
|
90
83
|
|
|
91
84
|
## 4. Bind to the server — fail closed
|
|
92
85
|
|
|
93
86
|
If the selected file's `cohort` is `unknown`, skip this check and go straight to section 5 — there
|
|
94
|
-
is no cohort to
|
|
87
|
+
is no cohort to look up either way, and the mismatch remediation below would be misleading when
|
|
95
88
|
watching was never possible.
|
|
96
89
|
|
|
97
90
|
Otherwise, run `kcap whoami` and compare its server URL to `server_url`: lowercase scheme and host,
|
|
98
91
|
drop a default port (80 for http, 443 for https only), trim a trailing slash, compare the path
|
|
99
|
-
as-is. Match → continue to section 5. Mismatch or `whoami` failure →
|
|
92
|
+
as-is. Match → continue to section 5. Mismatch or `whoami` failure → make **NO** eval lookup.
|
|
100
93
|
CLOSE with the file's links and this remediation: start your agent from a shell where `kcap whoami`
|
|
101
94
|
reports `<server_url>` — set `KCAP_PROFILE=<profile>`, unset `KCAP_URL`, and set `KCAP_CONFIG_DIR`
|
|
102
95
|
if kcap uses a custom config directory — then prompt again.
|
|
103
96
|
|
|
104
97
|
## 5. Watch the cohort
|
|
105
98
|
|
|
106
|
-
Cohort = `session_ids` (`cohort: unknown` or empty → CLOSE with links, no
|
|
107
|
-
the entries of `foreground_succeeded_ids` that are also in `session_ids
|
|
108
|
-
imported while the user watched setup, and the ones this watch waits on.
|
|
109
|
-
count. A foreground entry missing from `session_ids` is never
|
|
110
|
-
"M of the sessions that imported first are outside the 500 this
|
|
111
|
-
"
|
|
112
|
-
|
|
113
|
-
most
|
|
99
|
+
Cohort = `session_ids` (`cohort: unknown` or empty → CLOSE with links, no lookup); N is its size.
|
|
100
|
+
Foreground = the entries of `foreground_succeeded_ids` that are also in `session_ids`, in file
|
|
101
|
+
order: the sessions that imported while the user watched setup, and the ones this watch waits on.
|
|
102
|
+
K is the foreground count. A foreground entry missing from `session_ids` is never looked up; when
|
|
103
|
+
any are missing, say "M of the sessions that imported first are outside the 500 this import
|
|
104
|
+
recorded".
|
|
105
|
+
|
|
106
|
+
**Watched set** W, at most 25 sessions: the first 25 foreground sessions, then — only while fewer
|
|
107
|
+
than 25 — the other cohort sessions in file order. Open with: "Watching W of the N sessions from
|
|
108
|
+
this import; waiting for the K that imported first to be evaluated". When K > 25 add "the first 25
|
|
109
|
+
of them"; for `partial_exact` add "the sessions that imported first and the most recent others,
|
|
110
|
+
500 at most; older ones may land and evaluate unobserved"; if `unattributed_on_disk` > 0 add the
|
|
114
111
|
sentence from section 7.
|
|
115
112
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
poll — nothing from it commits — and counts as one failure toward the two-failure stop rule.
|
|
140
|
-
|
|
141
|
-
A 429 fails the poll. If its text matches `retry after (\d+)s`, wait that many seconds before the
|
|
142
|
-
next poll; otherwise wait 60 seconds. Never poll sooner than the 30-second cadence either way. HTTP
|
|
143
|
-
403 with `analytics_not_in_plan` → CLOSE immediately with the plan sentence (section 6); no
|
|
144
|
-
polling, no retry, no wait.
|
|
145
|
-
|
|
146
|
-
Progress = cohort ids that arrived / cohort size, and foreground ids evaluated / K, both computed
|
|
147
|
-
from the batch rows only — never a separate count, never repo- or tenant-wide. Cadence: first
|
|
148
|
-
snapshot immediately, then every 30 seconds. Say the progress after each poll.
|
|
149
|
-
|
|
150
|
-
**Baseline**: the first snapshot's rows. An eval present there is *pre-existing*; one whose
|
|
151
|
-
`eval_run_id` was null or absent there and non-null in a later poll *completed during this watch*.
|
|
152
|
-
Every summary labels each session with one of those two phrases.
|
|
113
|
+
**One poll** = ONE `get_session_evals` call with `session_ids` set to W — never two in flight. Each
|
|
114
|
+
entry's `state` is one of:
|
|
115
|
+
- `not_found` — not ingested yet (or not visible to you);
|
|
116
|
+
- `not_evaluated` — arrived, no eval yet;
|
|
117
|
+
- `queued` — arrived, eval waiting for a worker or a retry (`queue_position`, `next_attempt_at`);
|
|
118
|
+
- `running` — arrived, eval in progress (`questions_done` of `total_questions`);
|
|
119
|
+
- `completed` — arrived and evaluated: `eval_run_id`, `evaluated_at`, `overall_score` (out of 5),
|
|
120
|
+
`judge_model`, `summary`, `categories`, `weakest_questions`;
|
|
121
|
+
- `failed` — arrived, the eval run failed (`failure_reason`);
|
|
122
|
+
- `error` — this lookup failed.
|
|
123
|
+
|
|
124
|
+
Arrived = any state but `not_found` and `error`. A tool error (including a login prompt), or any
|
|
125
|
+
`error` entry, fails the poll: nothing from it commits, and it counts toward the two-failure stop
|
|
126
|
+
rule. If the tool is missing — no `kcap-sessions` MCP, or one without `get_session_evals` — this
|
|
127
|
+
kcap is older than the skill: say to update kcap and restart the agent, then CLOSE.
|
|
128
|
+
|
|
129
|
+
Progress = watched sessions arrived / W and foreground sessions evaluated / min(K, 25), from the
|
|
130
|
+
poll's entries only. Cadence: first snapshot immediately, then every 30 seconds. Say the progress
|
|
131
|
+
after each poll.
|
|
132
|
+
|
|
133
|
+
**Baseline**: the first snapshot. A session `completed` there is *pre-existing*; one that was not
|
|
134
|
+
`completed` there, or completed with a different `eval_run_id`, and is `completed` in a later poll
|
|
135
|
+
*completed during this watch*. Every summary labels each session with one of those two phrases.
|
|
153
136
|
|
|
154
137
|
**Stop**, evaluated in this order after each poll whose results have already committed:
|
|
155
|
-
1. K > 0 and every foreground session
|
|
138
|
+
1. K > 0 and every watched foreground session is `completed` → summarize all of them, ordered by
|
|
156
139
|
`evaluated_at` then `session_id`. A pre-existing eval counts: the wait is for these sessions to
|
|
157
140
|
be evaluated, whenever that happened.
|
|
158
|
-
2. K = 0 and three
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
3. `cohort: exact`,
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
Never fires for `partial_exact` or an empty cohort.
|
|
141
|
+
2. K = 0 and three watched sessions completed during this watch → summarize those three, ordered by
|
|
142
|
+
`evaluated_at` then `session_id`. Pre-existing evals never satisfy this rule: on a re-import they
|
|
143
|
+
belong to an earlier run, and stopping on them would end the watch before this import produced
|
|
144
|
+
anything.
|
|
145
|
+
3. `cohort: exact`, N ≤ 25, and every cohort session is `completed` → summarize the foreground
|
|
146
|
+
sessions, or with K = 0 the three with the newest `evaluated_at` (ties by `session_id`). This
|
|
147
|
+
rule may fire on the first snapshot with nothing but pre-existing evals: a cohort that is
|
|
148
|
+
already fully evaluated has nothing left to wait for, and the labels say so.
|
|
167
149
|
4. Two consecutive failed polls → stop, reporting the failures.
|
|
168
150
|
5. 10 minutes since the first snapshot → stop. No new poll starts after the deadline, but a poll
|
|
169
151
|
already dispatched before it finishes normally, and its outcome is still checked against rules
|
|
170
152
|
1–4 first. On a deadline stop, summarize the foreground sessions that did complete and name the
|
|
171
|
-
ones still pending, with
|
|
172
|
-
|
|
153
|
+
ones still pending, with their state; if none of them completed, summarize instead up to three
|
|
154
|
+
watched sessions with the newest `evaluated_at` (ties by `session_id`).
|
|
173
155
|
|
|
174
156
|
No idle early-stop — quiet polls are normal and are not a reason to stop early. Evals take minutes
|
|
175
157
|
per session, and the foreground sessions are the newest, so they are usually the last to complete.
|
|
176
158
|
|
|
177
|
-
**
|
|
178
|
-
the
|
|
179
|
-
|
|
180
|
-
`
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
Strongest = highest mean, weakest = lowest, ties alphabetical by category. A truncated or failed
|
|
191
|
-
detail query, or a session with no assessed rows, → summarize that session by `overall_score` alone
|
|
192
|
-
and say so; this never affects poll success or the stop rules above.
|
|
193
|
-
|
|
194
|
-
**What a detailed session summary says**, one short paragraph each: the link (section 7), the
|
|
195
|
-
baseline label, then vendor and model, length (`duration_min`, rounded, and `event_count`),
|
|
196
|
-
`overall_score` out of 5 and the judge model, strongest and weakest category with their means, and
|
|
197
|
-
the two weakest questions with their scores. When the `kcap-sessions` MCP is available, call `get_session_summary` once per
|
|
198
|
-
summarized session and lead with its title or first sentence when it returns one; an empty summary
|
|
199
|
-
is left out silently, never called "no summary".
|
|
200
|
-
|
|
201
|
-
**Cohort facts**, one line after the summaries, from the last committed poll's rows only: sessions
|
|
202
|
-
arrived out of N, sessions evaluated, and the mean `overall_score` across the evaluated ones.
|
|
159
|
+
**What a session summary says.** The first five sessions in summary order get one short paragraph
|
|
160
|
+
each: the link (section 7), the baseline label, `overall_score` out of 5 and the judge model, the
|
|
161
|
+
strongest and weakest of `categories` by `score` (ties alphabetical by name), the two
|
|
162
|
+
`weakest_questions` with their scores, and the gist of the judge's `summary`. When
|
|
163
|
+
`get_session_summary` returns a title or a first sentence for the session, lead with it; an empty
|
|
164
|
+
summary is left out silently, never called "no summary". Every later session gets a one-line entry
|
|
165
|
+
— link, label and `overall_score`. A completed entry with no categories is summarized by
|
|
166
|
+
`overall_score` alone; say so.
|
|
167
|
+
|
|
168
|
+
**Cohort facts**, one line after the summaries, from the last committed poll only: watched
|
|
169
|
+
sessions arrived out of W, sessions evaluated, and the mean `overall_score` across the evaluated
|
|
170
|
+
ones.
|
|
203
171
|
|
|
204
172
|
## 6. When little or nothing completes
|
|
205
173
|
|
|
206
174
|
Explain the real gates plainly: auto-eval may be off for a repository; the server needs an eval
|
|
207
175
|
agent configured; sessions under the minimum event count are skipped; already-evaluated sessions
|
|
208
|
-
are not re-run; a recovery sweep runs hourly.
|
|
209
|
-
immediately with the block below.
|
|
210
|
-
|
|
211
|
-
Plan sentence (used here and from sections 3 and 5): "Insights isn't in this workspace's plan, so
|
|
212
|
-
evals can't be followed from here; your import continues and evals appear in the Capacitor UI."
|
|
176
|
+
are not re-run; a recovery sweep runs hourly. A `failed` session names its `failure_reason`.
|
|
213
177
|
|
|
214
178
|
## 7. CLOSE — always
|
|
215
179
|
|
|
216
180
|
1. How to keep watching: prompt `Follow my kcap import` again (with the same `(run: <id>)` line
|
|
217
181
|
when you were bound to one).
|
|
218
|
-
2. Links:
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
once logged in.
|
|
182
|
+
2. Links: `<server_url>/sessions/<session_id>?tab=evaluation` per session; all results
|
|
183
|
+
`<server_url>/sessions`. No valid file → `server_url` from `kcap whoami`; if that fails too, say
|
|
184
|
+
the results live in the Capacitor server UI and that `kcap whoami` prints the URL once logged
|
|
185
|
+
in.
|
|
223
186
|
3. When `unattributed_on_disk` > 0: "N sessions on disk had no repository match; any of them that
|
|
224
187
|
imported show without one — `kcap remap` places them."
|
|
225
188
|
4. Offer the guided tour with the exact prompt `Start kcap guided tour`.
|
|
@@ -8,7 +8,8 @@ description: >-
|
|
|
8
8
|
this skill (and do NOT call the flows MCP tools) for an ordinary review
|
|
9
9
|
request such as "review my PR", "review this diff/spec/design", or "code
|
|
10
10
|
review" where the user just wants you to review it yourself — perform that
|
|
11
|
-
review directly instead.
|
|
11
|
+
review directly instead. For any other catalogue flow, or a flow offered
|
|
12
|
+
from your session context, use `agent-flows`.
|
|
12
13
|
---
|
|
13
14
|
|
|
14
15
|
# Review Flows
|
|
@@ -156,7 +157,10 @@ After applying the role-surface safety gate, if `start_review_flow` / `submit_re
|
|
|
156
157
|
## Workflow
|
|
157
158
|
|
|
158
159
|
```
|
|
159
|
-
|
|
160
|
+
get_flow_definition(kind)
|
|
161
|
+
→ follow its guide: what to submit, how to iterate (a server that publishes no guides says so; the rest of this skill applies)
|
|
162
|
+
|
|
163
|
+
start_review_flow(kind, target_kind, target_ref, target_title, session_title, context)
|
|
160
164
|
→ reviewer returns a result: findings (with the findings text) | clean
|
|
161
165
|
|
|
162
166
|
if clean:
|
|
@@ -176,7 +180,7 @@ if findings:
|
|
|
176
180
|
|
|
177
181
|
| Tool | Required args | Optional args | When to call |
|
|
178
182
|
|---|---|---|---|
|
|
179
|
-
| `start_review_flow` | `kind` (`spec-review`\|`code-review`), `target_kind` (what is being reviewed: `spec`, `code`, `pr`, `branch`, `file`, etc.), `target_ref` (a path, branch name, or PR URL/number that identifies the target), `target_title` (short human-readable title, e.g. spec name or PR title), `context` (background context: what to focus on, constraints, definition of done) | `vendor` (explicit reviewer vendor; omit to use the definition's authored vendor, or your saved `flows.reviewer_vendor` preference if it declares none), `model` (explicit reviewer model override — REQUIRES `vendor`; only pass it when the user named a model), `instructions`, `mode` (`context-only` — optional) | Once, at the start of a review task. |
|
|
183
|
+
| `start_review_flow` | `kind` (`spec-review`\|`code-review`), `target_kind` (what is being reviewed: `spec`, `code`, `pr`, `branch`, `file`, etc.), `target_ref` (a path, branch name, or PR URL/number that identifies the target), `target_title` (short human-readable title, e.g. spec name or PR title), `session_title` (the reviewer session's title: a short phrase naming this review, specific enough to tell it apart from other sessions — it replaces the generic "Review this PR/code" name), `context` (background context: what to focus on, constraints, definition of done) | `vendor` (explicit reviewer vendor; omit to use the definition's authored vendor, or your saved `flows.reviewer_vendor` preference if it declares none), `model` (explicit reviewer model override — REQUIRES `vendor`; only pass it when the user named a model), `instructions`, `mode` (`context-only` — optional) | Once, at the start of a review task. |
|
|
180
184
|
| `submit_review_round` | `flow_run_id`, `context` | `instructions` | After addressing findings. Pass the same `flow_run_id` and the updated context. |
|
|
181
185
|
| `get_review_flow_status` | — | `flow_run_id` (omit to read the newest open flow this session started, or on a harness without a session identity the newest one started from this workspace; several open flows are listed instead), `session_id` (look up another session's flows; defaults to this session), `wait` (`true`/`false`, defaults to `false`) — when `true`, blocks until the round is terminal or roughly 3.5 minutes pass, instead of returning the current snapshot immediately | Poll or check the current status of a flow (running, waiting, completed, failed). Use `wait: true` to ride out a long round instead of polling repeatedly yourself, and omit `flow_run_id` to recover a flow whose id you never received or lost. |
|
|
182
186
|
| `close_review_flow` | `flow_run_id` | — | Only after the reviewer returns `clean`. |
|
|
@@ -184,13 +188,14 @@ if findings:
|
|
|
184
188
|
## Example (code review)
|
|
185
189
|
|
|
186
190
|
```
|
|
187
|
-
# Step 1 — start (all
|
|
191
|
+
# Step 1 — start (all six args required; the reviewer sees a mirror of THIS SESSION's
|
|
188
192
|
# project directory, not of the directory you are working in — pass mode="context-only" to opt out)
|
|
189
193
|
start_review_flow(
|
|
190
194
|
kind="code-review",
|
|
191
195
|
target_kind="branch",
|
|
192
196
|
target_ref="feature/add-null-check",
|
|
193
197
|
target_title="Add null check on user input",
|
|
198
|
+
session_title="Review the null check on user input",
|
|
194
199
|
context="Review the diff on this branch for correctness and adherence to project conventions."
|
|
195
200
|
)
|
|
196
201
|
# → returns flow_run_id, e.g. "flow_abc123"
|
|
@@ -88,6 +88,10 @@ Call `start_agent` once for each agent.
|
|
|
88
88
|
should work in. A path inside a worktree counts as the repository the
|
|
89
89
|
worktree belongs to.
|
|
90
90
|
- `prompt`: the whole task. See the next section.
|
|
91
|
+
- `title`: required. A short phrase naming this agent's task, specific
|
|
92
|
+
enough to tell its session apart from the others in the repository. It is
|
|
93
|
+
the session's title from the start, and titles generated later do not
|
|
94
|
+
replace it.
|
|
91
95
|
- `work_item`: required, and there is no default. Pass the `wi:` or `le:` key
|
|
92
96
|
exactly as `get_next_work` printed it; or a work item id; or `requester` to
|
|
93
97
|
use the work item this session is attached to; or `none`. Leaving it out is
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kurrent/kcap",
|
|
3
|
-
"version": "1.3.0-beta.
|
|
3
|
+
"version": "1.3.0-beta.7",
|
|
4
4
|
"description": "CLI companion for Kurrent Capacitor — records and visualizes Claude Code sessions",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"repository": {
|
|
@@ -14,17 +14,17 @@
|
|
|
14
14
|
"postinstall": "node bin/postinstall.js"
|
|
15
15
|
},
|
|
16
16
|
"optionalDependencies": {
|
|
17
|
-
"@kurrent/kcap-darwin-arm64": "1.3.0-beta.
|
|
18
|
-
"@kurrent/kcap-linux-arm64": "1.3.0-beta.
|
|
19
|
-
"@kurrent/kcap-linux-musl-arm64": "1.3.0-beta.
|
|
20
|
-
"@kurrent/kcap-linux-musl-x64": "1.3.0-beta.
|
|
21
|
-
"@kurrent/kcap-linux-x64": "1.3.0-beta.
|
|
22
|
-
"@kurrent/kcap-win-x64": "1.3.0-beta.
|
|
17
|
+
"@kurrent/kcap-darwin-arm64": "1.3.0-beta.7",
|
|
18
|
+
"@kurrent/kcap-linux-arm64": "1.3.0-beta.7",
|
|
19
|
+
"@kurrent/kcap-linux-musl-arm64": "1.3.0-beta.7",
|
|
20
|
+
"@kurrent/kcap-linux-musl-x64": "1.3.0-beta.7",
|
|
21
|
+
"@kurrent/kcap-linux-x64": "1.3.0-beta.7",
|
|
22
|
+
"@kurrent/kcap-win-x64": "1.3.0-beta.7"
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
25
25
|
"bin/",
|
|
26
26
|
"kcap/"
|
|
27
27
|
],
|
|
28
|
-
"kcapReleaseCommit": "
|
|
29
|
-
"kcapReleaseTag": "v1.3.0-beta.
|
|
28
|
+
"kcapReleaseCommit": "ea55466b11f901d54ed75d89900f6b316e86dd33",
|
|
29
|
+
"kcapReleaseTag": "v1.3.0-beta.7"
|
|
30
30
|
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: suggest-review-flow
|
|
3
|
-
description: >-
|
|
4
|
-
Use this skill when implementation is complete — a feature or bugfix is functionally
|
|
5
|
-
finished, tests pass, or you are about to commit / open a PR / merge — or when a spec is
|
|
6
|
-
finalized. At that moment, proactively OFFER an independent second-harness review even if
|
|
7
|
-
the user did not ask, because a fresh, separate reviewer catches what the author's own model
|
|
8
|
-
misses. It calls list_reviewer_vendors to recommend a reviewer that will actually run for
|
|
9
|
-
this repo, offers a spec-review or code-review flow, and hands off to the review-flows skill
|
|
10
|
-
only after the user accepts — it never starts a flow itself. Do NOT use it when the user
|
|
11
|
-
asks you to review something yourself ("review this", "code review this", "look over my
|
|
12
|
-
spec"), or mid-task before the work is finished.
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
# Suggest a review flow
|
|
16
|
-
|
|
17
|
-
You have reached a milestone where an **independent** review adds real value: a
|
|
18
|
-
separate coding-agent session, with none of this session's context, reviews the
|
|
19
|
-
work — and a different model catches what the author's own model glossed over.
|
|
20
|
-
Most people never think to do this. Your job here is to **offer** it at the
|
|
21
|
-
right moment, recommend a reviewer that will actually run, and — only if the
|
|
22
|
-
user says yes — hand off to the `review-flows` skill. **This skill never starts
|
|
23
|
-
a review flow itself.**
|
|
24
|
-
|
|
25
|
-
## When to offer (and when not to)
|
|
26
|
-
|
|
27
|
-
Offer at exactly two milestones:
|
|
28
|
-
|
|
29
|
-
- **Spec complete** — you just produced AND presented a finalized spec/design
|
|
30
|
-
this session → offer a `spec-review` flow.
|
|
31
|
-
- **Implementation complete** — the change is functionally finished (you say so,
|
|
32
|
-
or you are about to commit / open a PR / merge) → offer a `code-review` flow.
|
|
33
|
-
|
|
34
|
-
Do NOT offer (stay silent) when:
|
|
35
|
-
|
|
36
|
-
- The user asked you to **review something yourself** ("review this", "code
|
|
37
|
-
review this", "look over the spec"). Just perform that review locally — no
|
|
38
|
-
offer, no flow.
|
|
39
|
-
- You are only part-way through: rough mid-stream brainstorming, a partial plan,
|
|
40
|
-
a routine edit, or work whose known checks are still failing.
|
|
41
|
-
- A review flow for this artifact is already engaged, active, or just completed.
|
|
42
|
-
- Another skill (brainstorming, writing-plans, finishing-a-development-branch,
|
|
43
|
-
requesting-code-review) is mid-flow — let it finish; offer at the seam.
|
|
44
|
-
|
|
45
|
-
**Offer at most once per artifact.** Key the offer on (milestone type + the
|
|
46
|
-
target's identity + its revision): the same spec or the same change never gets
|
|
47
|
-
offered twice, but a materially revised artifact may be offered again, and a
|
|
48
|
-
second, different artifact of the same kind may be offered on its own. If the
|
|
49
|
-
user declines or moves on, stay silent for that artifact. A failed availability
|
|
50
|
-
lookup counts as the one prompt for that artifact — do not re-prompt.
|
|
51
|
-
|
|
52
|
-
## How to recommend a reviewer
|
|
53
|
-
|
|
54
|
-
1. Call **`list_reviewer_vendors`** (read-only; safe to call before offering).
|
|
55
|
-
It returns `reviewers[]` (vendors that can actually run for this repo now),
|
|
56
|
-
`driver_vendor` (the harness you are running in, or absent if unknown), and
|
|
57
|
-
`diagnostics`.
|
|
58
|
-
2. **Prefer a reviewer different from the driver.** A different model is the
|
|
59
|
-
highest-value review. If one non-driver reviewer is available, recommend it;
|
|
60
|
-
if several, offer a short choice — never assert one vendor is "better".
|
|
61
|
-
3. **If the only available reviewer is your own vendor, still offer it** —
|
|
62
|
-
framed as an independent, context-free reviewer session. The value is the
|
|
63
|
-
clean second look, not necessarily a different model.
|
|
64
|
-
4. **If `driver_vendor` is absent (unknown)**, do NOT claim "a different model";
|
|
65
|
-
frame the offer as "a separate, independent reviewer session" and offer a
|
|
66
|
-
choice from `reviewers[]`.
|
|
67
|
-
5. **If `reviewers[]` is empty**, read `diagnostics.reason` and give one line of
|
|
68
|
-
guidance instead of a dead end:
|
|
69
|
-
- `no_daemons_connected` → start a daemon (`kcap daemon start -d`).
|
|
70
|
-
- `no_repo_hosting_daemon` → run a daemon on a machine that has this repo.
|
|
71
|
-
- `no_unattended_reviewer` → install/certify a second harness as a reviewer.
|
|
72
|
-
- `repo_unresolved` → the current directory isn't a recognized repo.
|
|
73
|
-
- `lookup_failed` → couldn't reach the server; suggest checking `kcap status`.
|
|
74
|
-
- `schema_skew` → the kcap client/server is out of date; suggest updating.
|
|
75
|
-
|
|
76
|
-
## Handing off (only after the user accepts)
|
|
77
|
-
|
|
78
|
-
- You MAY run the read-only `list_reviewer_vendors` lookup automatically, but you
|
|
79
|
-
**MUST NOT start a review flow until the user affirmatively accepts THIS
|
|
80
|
-
offer.**
|
|
81
|
-
- On acceptance, invoke the **`review-flows`** skill to run it, preserving the
|
|
82
|
-
chosen `kind` (spec-review / code-review), the target, and the chosen reviewer
|
|
83
|
-
vendor.
|
|
84
|
-
- If the reviewer vendor turns out to be unavailable at start (a snapshot race),
|
|
85
|
-
`review-flows` surfaces the reason — do not silently substitute another vendor;
|
|
86
|
-
re-recommend and get fresh consent.
|
|
87
|
-
|
|
88
|
-
## If `list_reviewer_vendors` is not available
|
|
89
|
-
|
|
90
|
-
Your harness caches the kcap MCP tool list when it connects. If kcap was
|
|
91
|
-
upgraded mid-session, `list_reviewer_vendors` may be missing from this session.
|
|
92
|
-
Do NOT guess availability and do NOT shell out as a workaround — tell the user
|
|
93
|
-
to restart the harness (or reconnect the `kcap-flows` MCP server) so the tool
|
|
94
|
-
appears, then offer again.
|