@kurrent/kcap 1.3.0-beta.5 → 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 CHANGED
@@ -1,6 +1,6 @@
1
- // Refreshes kcap's user-scope coding-agent installs so users pick up new or updated
2
- // skills, Codex/Cursor/Copilot hook commands, the Pi live-ingest extension, and
3
- // Claude plugin registration.
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,150 +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. Shared platform/binary resolution lives in resolve.js instead.
13
+ // exports.
14
14
 
15
15
  const { spawnSync } = require("child_process");
16
- const path = require("path");
17
- const fs = require("fs");
18
16
 
19
- // One entry per agent. Order is independent — each refresh is gated by its own
20
- // marker via `--if-installed`, which no-ops unless the user has previously
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.
24
- const REFRESHES = [
25
- ["plugin", "install", "--skills", "--if-installed"],
26
- ["plugin", "install", "--codex", "--if-installed"],
27
- ["plugin", "install", "--cursor", "--if-installed"],
28
- ["plugin", "install", "--copilot", "--if-installed"],
29
- ["plugin", "install", "--pi", "--if-installed"], // Pi extension (~/.pi/agent/extensions/kcap.ts)
30
- ["plugin", "install", "--opencode", "--if-installed"], // OpenCode plugin (~/.config/opencode/plugins/kcap.ts)
31
- ["plugin", "install", "--gemini", "--if-installed"], // Gemini hooks/MCP/instructions (~/.gemini)
32
- ["plugin", "install", "--kiro", "--if-installed"], // Kiro agent hooks (~/.kiro/agents/kcap.json)
33
- ["plugin", "install", "--antigravity", "--if-installed"], // Antigravity hooks (~/.gemini/config/plugins/kcap)
34
- ["plugin", "install", "--if-installed"], // Claude
35
- ];
17
+ // Above the binary's own worst case: eleven steps, each bounded at 60s.
18
+ const REFRESH_TIMEOUT_MS = 15 * 60_000;
36
19
 
37
- // Runs each refresh via the given launcher (an absolute path to kcap.js).
38
- // Each refresh runs independently: a failure, timeout, or unexpected exit code
39
- // from one never prevents the others and never throws to the caller — a failed
40
- // refresh must never break `npm install` or report `kcap update` as failed.
41
- function runRefreshes(launcherPath) {
42
- // Point the shipped Claude plugin's MCP entries at the native binary. Runs
43
- // here because runRefreshes fires at exactly the two moments the plugin dir
44
- // has just been (re)written by npm: postinstall and `kcap update`.
45
- patchPluginMcpConfig(launcherPath);
46
-
47
- for (const argv of REFRESHES) {
48
- try {
49
- spawnSync(process.execPath, [launcherPath, ...argv], {
50
- stdio: "ignore",
51
- env: process.env,
52
- // Hard ceiling so a stalled child can never hang the caller.
53
- timeout: 60_000,
54
- killSignal: "SIGKILL",
55
- windowsHide: true,
56
- });
57
- } catch {
58
- // Never fail the caller.
59
- }
60
- }
61
- }
62
-
63
- // ── Claude plugin .mcp.json patch ───────────────────────────────────────────
64
- //
65
- // The plugin ships `"command": "kcap"`, which resolves to the node wrapper —
66
- // one resident Node runtime per MCP server per open Claude session (~25 MB
67
- // idle each). Rewriting the command to the resolved native binary makes Claude
68
- // spawn the binary directly. Best-effort: on any failure the shipped value
69
- // stays in place, which still works via the wrapper.
70
-
71
- // The servers shipped in the plugin's .mcp.json, keyed by canonical
72
- // `["mcp", <suffix>]` args. Only these exact name/args pairs are patched —
73
- // anything else in the file is preserved verbatim.
74
- const PLUGIN_MCP_SERVERS = {
75
- "kcap-review": "review",
76
- "kcap-sessions": "sessions",
77
- "kcap-flows": "flows",
78
- "kcap-memory": "memory",
79
- "kcap-workitems": "workitems",
80
- "kcap-plans": "plans",
81
- "kcap-artefacts": "artefacts",
82
- "kcap-analytics": "analytics",
83
- "kcap-knowledge": "knowledge",
84
- "kcap-handoff": "handoff",
85
- };
86
-
87
- // A command this patcher may rewrite: the shipped literal "kcap", or an
88
- // absolute path whose basename is the kcap binary (a previous patch that has
89
- // gone stale after an npm re-layout). Handles both path flavors so a stale
90
- // Windows path is still recognized. Anything else is a customization → keep.
91
- function isPatchableKcapCommand(command) {
92
- if (command === "kcap") return true;
93
- if (typeof command !== "string") return false;
94
- if (!path.posix.isAbsolute(command) && !path.win32.isAbsolute(command)) return false;
95
- const base = command.split(/[\\/]/).pop().toLowerCase();
96
- return base === "kcap" || base === "kcap.exe";
97
- }
98
-
99
- // Pure: rewrites in place the canonical plugin entries of `cfg` whose command
100
- // is patchable, returning whether anything changed. Throws on a shape that
101
- // isn't the plugin config (caller turns that into the single warning).
102
- function patchPluginMcpServers(cfg, binaryPath) {
103
- if (!cfg || typeof cfg !== "object" || Array.isArray(cfg)) {
104
- throw new Error("config is not an object");
105
- }
106
- const servers = cfg.mcpServers;
107
- if (!servers || typeof servers !== "object" || Array.isArray(servers)) {
108
- throw new Error("mcpServers is not an object");
109
- }
110
-
111
- let changed = false;
112
- for (const [name, suffix] of Object.entries(PLUGIN_MCP_SERVERS)) {
113
- const entry = servers[name];
114
- if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
115
- if (!Array.isArray(entry.args) || entry.args.length !== 2 ||
116
- entry.args[0] !== "mcp" || entry.args[1] !== suffix) continue; // customized args → keep
117
- if (!isPatchableKcapCommand(entry.command)) continue; // customized command → keep
118
- if (entry.command === binaryPath) continue; // already current
119
- entry.command = binaryPath;
120
- changed = true;
121
- }
122
- return changed;
123
- }
124
-
125
- // Rewrites the plugin's shipped .mcp.json (a sibling `kcap/` dir of the
126
- // launcher's `bin/`) so Claude spawns the native binary directly. Validates
127
- // before writing, writes a sibling temp file, then renames atomically — the
128
- // original survives any pre-rename failure. Never throws; on failure it emits
129
- // ONE concise warning and leaves the shipped `"command": "kcap"` in place.
130
- // `binaryPath` is a test seam; real callers let it resolve.
131
- function patchPluginMcpConfig(launcherPath, binaryPath) {
132
- 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) {
133
25
  try {
134
- binaryPath = binaryPath || require("./resolve").resolveNativeBinary();
135
- if (!binaryPath) return; // unsupported platform / package missing — wrapper keeps working
136
-
137
- mcpJsonPath = path.join(path.dirname(launcherPath), "..", "kcap", ".mcp.json");
138
- if (!fs.existsSync(mcpJsonPath)) return; // dev checkout / plugin not shipped
139
-
140
- const cfg = JSON.parse(fs.readFileSync(mcpJsonPath, "utf8"));
141
- if (!patchPluginMcpServers(cfg, binaryPath)) return; // already patched / nothing canonical
142
-
143
- const tmp = `${mcpJsonPath}.tmp-${process.pid}-${Date.now()}`;
144
- try {
145
- fs.writeFileSync(tmp, JSON.stringify(cfg, null, 2) + "\n");
146
- fs.renameSync(tmp, mcpJsonPath);
147
- } catch (e) {
148
- try { fs.unlinkSync(tmp); } catch {}
149
- throw e;
150
- }
151
- } catch (e) {
152
- console.warn(
153
- `kcap: could not point the Claude plugin MCP entries at the native binary` +
154
- ` (${e && e.message ? e.message : e}); they will keep launching via the node wrapper.`,
155
- );
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.
156
40
  }
157
41
  }
158
42
 
159
- module.exports = { runRefreshes, patchPluginMcpConfig, patchPluginMcpServers, isPatchableKcapCommand };
43
+ module.exports = { runRefreshes };
package/bin/resolve.js CHANGED
@@ -1,10 +1,5 @@
1
- // Side-effect-free platform/native-binary resolution, shared by kcap.js (the
2
- // launcher) and refresh.js (postinstall / `kcap update` refresh).
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");
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "kcap",
3
- "version": "1.3.0-beta.5",
3
+ "version": "1.3.0-beta.7",
4
4
  "description": "Records and visualizes Claude Code sessions via kcap CLI hooks"
5
5
  }
package/kcap/.mcp.json CHANGED
@@ -15,7 +15,7 @@
15
15
  "command": "kcap",
16
16
  "args": ["mcp", "flows"],
17
17
  "cwd": "${CLAUDE_PROJECT_DIR}",
18
- "description": "Structured AI agent flows — start_review_flow, submit_review_round, get_review_flow_status, close_review_flow (review-specific) plus their generic equivalents start_flow, send_to_participant, get_flow_status, close_flow (any flow-definition catalog id). Launches a SEPARATE hosted participant agent through your daemon and iterates to sign-off; requires `kcap login` and a running daemon with this repo checked out (the tools are inert otherwise). Use only when the user explicitly asks for a review flow / agent flow / to submit for review — for an ordinary 'review my PR' or 'code review' request, review directly and do not call these tools."
18
+ "description": "Structured AI agent flows — start_review_flow, submit_review_round, get_review_flow_status, close_review_flow (review-specific) plus their generic equivalents start_flow, send_to_participant, get_flow_status, close_flow (any flow-definition catalog id). Launches a SEPARATE hosted participant agent through your daemon and iterates to sign-off; requires `kcap login` and a running daemon with this repo checked out (the tools are inert otherwise). Use the flow tools only when the user explicitly asks for a review flow / agent flow / to submit for review — for an ordinary 'review my PR' or 'code review' request, review directly and do not call these tools. Also list_start_agent_options and start_agent: when the user asks to start a separate hosted agent that works on its own, use these — not your harness's own subagent tool, a flow, or the `kcap agent start` CLI."
19
19
  },
20
20
  "kcap-memory": {
21
21
  "command": "kcap",
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
 
@@ -79,6 +79,16 @@
79
79
  "async": true
80
80
  }
81
81
  ]
82
+ },
83
+ {
84
+ "matcher": "Read",
85
+ "hooks": [
86
+ {
87
+ "type": "command",
88
+ "command": "kcap hook --claude --plan-read --no-update-check",
89
+ "timeout": 3
90
+ }
91
+ ]
82
92
  }
83
93
  ],
84
94
  "PostToolUseFailure": [
@@ -1,24 +1,23 @@
1
1
  ---
2
2
  name: agent-flows
3
3
  description: >-
4
- This skill should be used ONLY when the user explicitly asks to run a
5
- structured agent *flow* by name or definition id — e.g. "start a flow",
6
- "run the code-review flow", "run the X flow", "use flow definition X",
7
- "kick off an agent flow", or wants an iterative loop run by a separate
8
- hosted participant agent that continues until sign-off. It covers the same
9
- underlying tools as the `review-flows` skill (`start_review_flow` etc. are
10
- aliases of the generic tools documented here) — use `review-flows` for the
11
- two built-in review kinds (`spec-review`, `code-review`) and this skill for
12
- any other flow definition, or when the user names a `definition_id`
13
- explicitly. Do NOT use this skill (and do NOT call the flows MCP tools) for
14
- an ordinary request such as "review my PR", "do X for me", or "check this
15
- over" where the user just wants you to do the work yourself — perform that
16
- work directly instead.
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`.
17
16
  ---
18
17
 
19
18
  # Agent Flows
20
19
 
21
- 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 only when the user explicitly opts into 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.
22
21
 
23
22
  ## Long rounds are normal
24
23
 
@@ -38,15 +37,14 @@ and end the reviewer turn. The hosted-reviewer contract wins over driver-looking
38
37
 
39
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.
40
39
 
41
- Only start a flow when the user explicitly asks for a flow — 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.
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.
42
41
 
43
42
  ## Choosing the flow definition
44
43
 
45
- Once the user has explicitly opted into a flow (see above), pick the `definition_id`:
44
+ Once the user has asked for a flow or accepted one you offered (see above), pick the `definition_id`:
46
45
 
47
- - Spec or design document → `definition_id: "spec-review"` (built-in; same as `review-flows`' `spec-review` kind)
48
- - Code changes or a pull request → `definition_id: "code-review"` (built-in; same as `review-flows`' `code-review` kind)
49
- - 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.
50
48
 
51
49
  For the reserved `spec-review` and `code-review` aliases, reviewer-vendor language is role-bound:
52
50
  pass the one vendor explicitly named as the reviewer, ignore driver-harness mentions, honor
@@ -87,6 +85,10 @@ vendor supports this: the daemon must advertise a runtime model resolver for the
87
85
  (Claude and Codex today; other vendors keep vendor-only overrides with no model choice) or the
88
86
  server rejects the override outright.
89
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
+
90
92
  ## Composing a dynamic flow
91
93
 
92
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`.)
@@ -146,7 +148,7 @@ After applying the role-surface safety gate, if `start_flow` / `send_to_particip
146
148
  5. **If participant output is unclear or requires user input**, pause and ask the user before proceeding.
147
149
  6. **Never start a nested flow.** If you are the hosted participant (see above), do not call these tools yourself.
148
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.
149
- 8. **For a code review flow (`definition_id: "code-review"`), do NOT ask the participant to run tests.** CI covers test execution; participant feedback is on correctness, design, and adherence to conventions.
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.
150
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.
151
153
 
152
154
  ## Pending messages
@@ -169,10 +171,17 @@ The server enforces per-run budgets; watch for these in tool error responses:
169
171
 
170
172
  ## Workflow
171
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
+
172
181
  Single-participant definitions start eagerly — round 1 runs as part of `start_flow`:
173
182
 
174
183
  ```
175
- 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)
176
185
  → participant returns a result: kind findings (with the result text) | kind clean
177
186
 
178
187
  if clean:
@@ -191,7 +200,7 @@ if findings:
191
200
  Multi-participant definitions start round-less — you address each role yourself, and the run is clean only in aggregate:
192
201
 
193
202
  ```
194
- 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)
195
204
  → no round yet — roles have not launched
196
205
 
197
206
  send_to_participant(flow_run_id, participant="reviewer", message=…)
@@ -217,7 +226,8 @@ report completion to user
217
226
  | Tool | Required args | Optional args | When to call |
218
227
  |---|---|---|---|
219
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. |
220
- | `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), `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. |
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. |
221
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. |
222
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. |
223
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. |
@@ -225,13 +235,14 @@ report completion to user
225
235
  ## Example (custom definition)
226
236
 
227
237
  ```
228
- # Step 1 — start (all five required args required; the participant sees a mirror of THIS SESSION's
238
+ # Step 1 — start (all six args required; the participant sees a mirror of THIS SESSION's
229
239
  # project directory, not of the directory you are working in — pass mode="context-only" to opt out)
230
240
  start_flow(
231
241
  definition_id="code-review",
232
242
  target_kind="branch",
233
243
  target_ref="feature/add-null-check",
234
244
  target_title="Add null check on user input",
245
+ session_title="Review the null check on user input",
235
246
  context="Review the diff on this branch for correctness and adherence to project conventions."
236
247
  )
237
248
  # → returns flow_run_id, e.g. "flow_abc123"
@@ -260,6 +271,7 @@ start_flow(
260
271
  target_kind="branch",
261
272
  target_ref="feature/add-null-check",
262
273
  target_title="Add null check on user input",
274
+ session_title="Review and test the null check on user input",
263
275
  context="Review the diff on this branch and write/run tests for the new code path."
264
276
  )
265
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 Capacitor analytics for exactly the sessions that import
8
- created, waits for the sessions that imported while the user watched to be
9
- evaluated, summarizes their evals, links to the results and offers the guided
10
- tour. Not for browsing evals in general — that is the analytics or guided-tour
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 query you
17
- issue names only those sessions — never a repo-wide or tenant-wide read, and never a query without
18
- an `IN (...)` or `session_id = '...'` bound to this cohort. If a response ever includes a row for a
19
- session id outside the cohort, discard that row: never count it, link it, or mention it.
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
- Three grammars gate everything below:
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 place in a query):
26
- `^[A-Za-z0-9_-]{1,128}$`.
27
- - **Repo hash** (the `repo_hash` field an analytics response returns, used only in the repo-scoped
28
- link form): `^[0-9a-f]{16}$`. A `repo_hash` that fails this never reaches a link — fall back to
29
- the no-repo-hash link form (section 7).
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 query. **Never fall through to
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 `skill_not_installed` or
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 query.
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 query if none
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; every entry of `session_ids` and
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 query.
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 query — an unverifiable
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 SQL, a path, or a link.
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 evidently have the skill
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 query either way, and the mismatch remediation below would be misleading when
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 → issue **NO** analytics query.
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 query). Foreground =
107
- the entries of `foreground_succeeded_ids` that are also in `session_ids`: the sessions that
108
- imported while the user watched setup, and the ones this watch waits on. K is the foreground
109
- count. A foreground entry missing from `session_ids` is never queried; when any are missing, say
110
- "M of the sessions that imported first are outside the 500 this watch can query". Open with:
111
- "Watching N sessions from this import; waiting for the K that imported first to be evaluated";
112
- for `partial_exact` add "the sessions that imported first and the most recent others, 500 at
113
- most; older ones may land and evaluate unobserved"; if `unattributed_on_disk` > 0 add the
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
- Every query uses `query_analytics` with `scope: 'global'` (the MCP defaults to the caller's cwd
117
- repo and will not widen on its own), **ONE call at a time — never two in flight** — and names only
118
- cohort ids, each already validated against the grammar above, as single-quoted literals in an
119
- `IN (...)` list or `session_id = '...'`. If a response ever includes a row whose `session_id` is
120
- not in `session_ids`, drop that row before using the response for anything.
121
-
122
- **Request budget:** at most 20 cohort queries per poll. `floor = ceil(N / 20)`. The FIRST poll uses
123
- batch size `floor` exactly — no probing at a smaller size first. Every batch passes `max_rows`
124
- equal to its own size:
125
-
126
- SELECT s.session_id, s.repo_hash, s.vendor, s.model, s.duration_min, s.event_count,
127
- e.eval_run_id, e.evaluated_at, e.overall_score, e.judge_model
128
- FROM v_an_sessions s LEFT JOIN v_an_eval_summaries e ON e.session_id = s.session_id
129
- WHERE s.session_id IN ('<id>', '<id>', ...)
130
-
131
- A row = arrived; a non-null `eval_run_id` = completed. Each response body carries `max_rows`, the
132
- server's effective cap. After the first poll: if any body reported `max_rows < floor`, fail closed
133
- at once — say the server's row cap is below what watching this many sessions needs, and CLOSE,
134
- having spent no more than the 20-query budget. Otherwise raise the batch to `min(100, max_rows)`
135
- for later polls. Any batch that comes back `truncated: true`, in the first poll or any later one,
136
- fails that poll — the cap decides, not the truncation flag alone.
137
-
138
- One poll = every batch it needs, each non-truncated. A failed or truncated batch discards the whole
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 has a completed eval → summarize all of them, ordered by
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 distinct cohort sessions completed during this watch → summarize those three,
159
- ordered by `evaluated_at` then `session_id`. Pre-existing evals never satisfy this rule: on a
160
- re-import they belong to an earlier run, and stopping on them would end the watch before this
161
- import produced anything.
162
- 3. `cohort: exact`, non-empty, and every id in `session_ids` has a completed eval → summarize the
163
- foreground sessions, or with K = 0 the three with the newest `evaluated_at` (ties by
164
- `session_id`). This rule may fire on the first snapshot with nothing but pre-existing evals:
165
- a cohort that is already fully evaluated has nothing left to wait for, and the labels say so.
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 whether each has arrived; if none of them completed, summarize instead
172
- up to three cohort sessions with the newest `evaluated_at` (ties by `session_id`).
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
- **Per-session detail** (one session per query, 2 queries per detailed session, at most 10 across
178
- the whole run). A foreground pass takes whole session chains, so K can exceed five: the first five
179
- sessions in summary order get detail; every later one gets a one-line entry — link, label and
180
- `overall_score` — and no detail query. Both queries pass `max_rows` explicitly — a query left at
181
- the agent's guess truncates on the category list and throws the detail away:
182
-
183
- -- max_rows: 25
184
- SELECT category, ROUND(AVG(score), 2) AS mean FROM v_an_eval_scores
185
- WHERE session_id = '<id>' AND outcome = 'assessed' GROUP BY category
186
- -- max_rows: 2
187
- SELECT question_id, score FROM v_an_eval_scores
188
- WHERE session_id = '<id>' AND outcome = 'assessed' ORDER BY score ASC, question_id ASC LIMIT 2
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. If the analytics MCP is absent entirely, close
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: with a `repo_hash` matching `^[0-9a-f]{16}$`, `<server_url>/repo/<repo_hash>/sessions/<session_id>?tab=evaluation`;
219
- otherwise (no `repo_hash`, or one that fails the grammar) `<server_url>/sessions/<session_id>?tab=evaluation`;
220
- all results `<server_url>/sessions`. No valid file → `server_url` from `kcap whoami`; if that
221
- fails too, say the results live in the Capacitor server UI and that `kcap whoami` prints the URL
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`.
@@ -34,9 +34,16 @@ through the `kcap-plans` MCP tools; nothing infers it. Three rules:
34
34
  While a plan's `is_complete` is `false`, never call `set_plan_tasks`
35
35
  on it for any reason — the list would be rebuilt from a view that is
36
36
  missing tasks.
37
- 3. **Keep whatever ledger your own workflow asks for as well.** These tools
38
- replace the harness's task list, not your notes or any file another
39
- workflow tells you to maintain.
37
+ 3. **Keep whatever ledger your own workflow asks for as well, and move both
38
+ together.** These tools replace the harness's task list, not your notes or
39
+ any file another workflow tells you to maintain — a subagent-driven
40
+ development `progress.md`, an executing-plans checklist. Pair every write to
41
+ that ledger with an `update_plan_task` in the same turn: `in_progress` when
42
+ you start or dispatch a task, `completed` when it passes its review rather
43
+ than when the work first comes back. The user watches the Capacitor ledger,
44
+ and a task finished only in your own file still reads as `pending` there.
45
+ When subagents do the tasks, the coordinating session makes these calls — a
46
+ subagent's own session is not on the plan.
40
47
 
41
48
  ## Resuming a plan
42
49
 
@@ -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
- start_review_flow(kind, target_kind, target_ref, target_title, context)
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 five required args required; the reviewer sees a mirror of THIS SESSION's
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"
@@ -0,0 +1,167 @@
1
+ ---
2
+ name: start-agents
3
+ description: >-
4
+ This skill should be used ONLY when the user explicitly asks for work to be
5
+ handed to separate agents — e.g. "start an agent for this", "start a hosted
6
+ agent", "start an agent for each of these", "hand this to another agent",
7
+ "run these in separate sessions". It covers `list_start_agent_options` and
8
+ `start_agent`, the `kcap mcp flows` tools that check this machine's daemon
9
+ and then start an ordinary hosted agent with a working directory and a
10
+ prompt, returning at once so the agent runs on its own. Use them INSTEAD of
11
+ your harness's own subagent or background-agent tool (which stays inside
12
+ this session), a flow, or the `kcap agent start` CLI. Do NOT use it for work
13
+ you can do yourself in this session, for an iterative review loop the user
14
+ asked for (use `review-flows`), or for a flow whose rounds you drive (use
15
+ `agent-flows`).
16
+ ---
17
+
18
+ # Start agents
19
+
20
+ `start_agent` hands one task to one **separate hosted agent**: an ordinary
21
+ hosted agent with its own session, its own worktree and its own context. The
22
+ user supervises it from the dashboard, as they supervise any hosted agent. You
23
+ start it and move on. You do not drive it, wait for it or read its result.
24
+
25
+ It is how a list of independent tasks, such as a set of loose ends or the next
26
+ steps of a work item, gets done without all of it landing in one context.
27
+
28
+ ## When to use it
29
+
30
+ Only when the user asks for separate agents. A list of tasks is not a request
31
+ to fan out: if the user asked you to fix something, fix it here.
32
+
33
+ Every started agent runs a paid model and takes a slot on the user's daemon.
34
+
35
+ ## Not these look-alikes
36
+
37
+ - Your harness's own subagent or background-agent tool (Claude Code's Agent
38
+ or Task tool, Codex's `spawn_agent`) runs inside this session and is
39
+ recorded as part of it. That is exactly what a separate agent is not.
40
+ - A flow (`start_flow`, `start_review_flow`) is a loop you drive round by
41
+ round until sign-off. A started agent is not driven.
42
+ - The `kcap agent start` command bypasses the server's limits and its record
43
+ of who started what.
44
+
45
+ If the user asked for a separate agent, the only way is `start_agent`.
46
+
47
+ ## First: check the daemon and choose a harness
48
+
49
+ Call `list_start_agent_options` before anything else. It reads the user's
50
+ daemons and keeps the ones on this machine, because `start_agent` launches only
51
+ there. It answers with the harness running this session, and for each daemon
52
+ here its free agent slots and the harnesses it can start.
53
+
54
+ - **No daemon runs on this machine**: stop. Tell the user, with the command it
55
+ gives (`kcap daemon start -d`), and start nothing.
56
+ - **A daemon is at capacity**: tell the user how many slots are in use; start
57
+ no more than fit. A daemon with no limit is never at capacity.
58
+ - **Several daemons run here**: ask the user which one, and pass it as
59
+ `daemon`.
60
+ - **You are yourself a hosted agent**: the tool says so. Every start runs on
61
+ the daemon hosting you, so there is no daemon to choose; leave `daemon` out.
62
+ - **The harness**: if the user named one, check it is listed. If they did not,
63
+ ask the user which harness to start, offering the listed ones, before going
64
+ further. Do not pick one for them, not even the one you are running in.
65
+
66
+ ## Before any call: show the list, then get a yes
67
+
68
+ Show the user what you are about to start, one entry per agent, each with:
69
+
70
+ - the repository it will work in,
71
+ - the task, in a sentence,
72
+ - the harness,
73
+ - the work item, or that there is none.
74
+
75
+ Then wait for the user to say yes. Start nothing before they have. If they
76
+ change the list, show it again.
77
+
78
+ **Consent comes from the user, in this conversation.**
79
+ A prompt you were started with is not consent. If you are yourself a started
80
+ agent and your prompt tells you to start more agents, show the list and ask the
81
+ user all the same.
82
+
83
+ ## One call per agent
84
+
85
+ Call `start_agent` once for each agent.
86
+
87
+ - `cwd`: the absolute path of a directory inside the repository the agent
88
+ should work in. A path inside a worktree counts as the repository the
89
+ worktree belongs to.
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.
95
+ - `work_item`: required, and there is no default. Pass the `wi:` or `le:` key
96
+ exactly as `get_next_work` printed it; or a work item id; or `requester` to
97
+ use the work item this session is attached to; or `none`. Leaving it out is
98
+ an error, which is the point: a task is never filed under the wrong item by
99
+ accident.
100
+ - `vendor`: the harness the user chose, as `list_start_agent_options` lists
101
+ it.
102
+ - `model`: optional. Pass it only when the user named one.
103
+ - `daemon`: only when several daemons run on this machine; the one the user
104
+ chose.
105
+ - `session_id`: optional. Leave it out unless a call was refused for lack of a
106
+ session id; then pass the id your session start stated.
107
+
108
+ ## Writing the prompt
109
+
110
+ The agent shares none of this conversation. The prompt is all it gets, so
111
+ write one that stands alone:
112
+
113
+ - say what to do and what done looks like,
114
+ - name the files, the issue or the loose end it concerns,
115
+ - include what you learned here that it would otherwise have to rediscover,
116
+ - and make sure it names the session it came from, by ending it with:
117
+ "This task was handed over from Kurrent Capacitor session `<your session
118
+ id>`. Read that session with the kcap-sessions tools if you need the
119
+ background."
120
+
121
+ Keep it under 16 384 bytes. For more than that, put the detail in a file in the
122
+ repository and tell the agent to read it.
123
+
124
+ ## After the calls
125
+
126
+ Each call answers `requested`, with the agent's id and the url of its page.
127
+ `requested` means the launch command was sent. It does not mean the agent is
128
+ running, and nothing is attached when the call returns: the server tries once,
129
+ later, to attach the new session to the work item you named.
130
+
131
+ Do not wait for the agents, and do not poll them. Do not call `start_agent`
132
+ again to find out whether an agent started.
133
+
134
+ Then report to the user:
135
+
136
+ - the url of every agent that was requested,
137
+ - every refusal, in the server's words.
138
+
139
+ ## Refusals
140
+
141
+ A refusal states its reason. Relay it; do not retry in a loop.
142
+
143
+ - `already_in_progress`: a start on the same key is in flight, or one was sent
144
+ in the last 30 seconds. Do not repeat it.
145
+ - `no_daemon_on_this_machine`: none of the user's daemons runs here, or the one
146
+ that does is too old to say which machine it is on. The user starts one with
147
+ `kcap daemon start -d`, or updates kcap and restarts the daemon.
148
+ - `ambiguous_daemon`: several daemons run here. Ask the user which, and pass
149
+ `daemon`.
150
+ - `vendor_unavailable`: the daemon does not host that harness. The refusal
151
+ lists the ones it does; ask the user to pick one of them.
152
+ - `daemon_at_capacity`, `start_limit_reached`: there is no room. Stop starting
153
+ agents and tell the user how many were requested.
154
+ - `work_item_resolved`: the item was merged or split. The message says where it
155
+ went, as far as you may see. Ask the user which item to use.
156
+ - `work_item_not_visible`, `session_not_found`: you named something that is not
157
+ there for you. Check the key.
158
+ - `failed`, or a call that timed out: the agent may or may not have started.
159
+ Tell the user to look at the agents page. Do not start it again unasked.
160
+ - "This server cannot start agents": the server does not offer the feature.
161
+ There is nothing to retry.
162
+
163
+ ## If `start_agent` is not among your tools
164
+
165
+ Tell the user to update kcap, run `kcap setup`, and restart the harness. Do not
166
+ start agents another way in its place: the limits and the record of who started
167
+ what belong to this tool.
@@ -89,6 +89,16 @@ end twice is a no-op (`created: false`). It refuses text shorter than 12 or long
89
89
  500 characters and "none"-style phrases — do not declare that there is nothing left.
90
90
  Loose ends are the user's; they are never converted into work items by this tool.
91
91
 
92
+ Name the issue it is about with an optional `subject` (`PROJ-123`, `#123`, `owner/repo#123`,
93
+ or a GitHub issue URL). When the server fetches it and finds it already closed, the result
94
+ says so and tells you to check the remote before treating the end as unfinished.
95
+
96
+ The feed files an end under a work item. An end that names an issue goes under that
97
+ issue's item, or stands alone when the issue has none. Otherwise it goes under this
98
+ session's primary item. When that is wrong, say where it belongs: `work_item_id` for a
99
+ known item with no issue of its own, or `standalone: true` when it belongs to none of
100
+ this session's work, such as an issue still to be filed. Set at most one of the two.
101
+
92
102
  When you finish a listed or declared loose end, close it with `close_loose_end`, naming it by
93
103
  the `loose_end_id` that `get_next_work`'s evidence or `list_loose_ends` shows. A later sighting
94
104
  of the same work reopens it on its own; `reopen_loose_end` undoes a mistaken close.
@@ -128,7 +138,7 @@ loose ends with `declare_loose_end` (one call per item, never "none"), then call
128
138
  | `declare_work_item` | exactly one of `issue_key` \| `pr_number` \| `work_item_id` \| `new_title` | Attach the session to a work item (or create one). `session_id` defaults to the current session. |
129
139
  | `get_session_work_items` | — | List what the current session is attached to. |
130
140
  | `get_next_work` | — | What the user should work on next, ranked, with because-clauses and evidence. `repo_hash` defaults to the current repository; `limit` defaults to 5 (max 20). |
131
- | `declare_loose_end` | `text` | Record one unfinished item in the user's next-work ledger. `session_id` defaults to the current session. |
141
+ | `declare_loose_end` | `text` | Record one unfinished item in the user's next-work ledger. `subject` optionally names the issue it is about; `work_item_id` or `standalone` says which item it belongs under. `session_id` defaults to the current session. |
132
142
  | `list_loose_ends` | — | List loose ends with their `loose_end_id`: `status` open (default) or closed, `repo_hash` defaults to the current repository, `limit` 20 (max 50), `cursor` from `next_cursor`. |
133
143
  | `close_loose_end` | `loose_end_id` | Mark a finished loose end done. `session_id` defaults to the current session. |
134
144
  | `reopen_loose_end` | `loose_end_id` | Undo a close. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kurrent/kcap",
3
- "version": "1.3.0-beta.5",
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.5",
18
- "@kurrent/kcap-linux-arm64": "1.3.0-beta.5",
19
- "@kurrent/kcap-linux-musl-arm64": "1.3.0-beta.5",
20
- "@kurrent/kcap-linux-musl-x64": "1.3.0-beta.5",
21
- "@kurrent/kcap-linux-x64": "1.3.0-beta.5",
22
- "@kurrent/kcap-win-x64": "1.3.0-beta.5"
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": "aa910d51b8f5272171eb1de51230179daf4c05f4",
29
- "kcapReleaseTag": "v1.3.0-beta.5"
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.