@kurrent/kcap 1.3.0-beta.6 → 1.3.0-beta.8

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,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. 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. 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 each refresh via the given launcher (an absolute path to kcap.js).
40
- // Each refresh runs independently: a failure, timeout, or unexpected exit code
41
- // from one never prevents the others and never throws to the caller — a failed
42
- // refresh must never break `npm install` or report `kcap update` as failed.
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
- binaryPath = binaryPath || require("./resolve").resolveNativeBinary();
137
- if (!binaryPath) return; // unsupported platform / package missing — wrapper keeps working
138
-
139
- mcpJsonPath = path.join(path.dirname(launcherPath), "..", "kcap", ".mcp.json");
140
- if (!fs.existsSync(mcpJsonPath)) return; // dev checkout / plugin not shipped
141
-
142
- const cfg = JSON.parse(fs.readFileSync(mcpJsonPath, "utf8"));
143
- if (!patchPluginMcpServers(cfg, binaryPath)) return; // already patched / nothing canonical
144
-
145
- const tmp = `${mcpJsonPath}.tmp-${process.pid}-${Date.now()}`;
146
- try {
147
- fs.writeFileSync(tmp, JSON.stringify(cfg, null, 2) + "\n");
148
- fs.renameSync(tmp, mcpJsonPath);
149
- } catch (e) {
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, 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.6",
3
+ "version": "1.3.0-beta.8",
4
4
  "description": "Records and visualizes Claude Code sessions via kcap CLI hooks"
5
5
  }
@@ -33,9 +33,9 @@
33
33
  "command": "kcap",
34
34
  "args": ["mcp", "handoff"]
35
35
  },
36
- "kcap-artefacts": {
36
+ "kcap-pages": {
37
37
  "command": "kcap",
38
- "args": ["mcp", "artefacts"]
38
+ "args": ["mcp", "pages"]
39
39
  },
40
40
  "kcap-knowledge": {
41
41
  "command": "kcap",
package/kcap/.mcp.json CHANGED
@@ -40,9 +40,9 @@
40
40
  "args": ["mcp", "handoff"],
41
41
  "description": "Continue a session whose agent is gone — continue_session attaches this session to that session's work items and unfinished plans, refusing while it may still be running."
42
42
  },
43
- "kcap-artefacts": {
43
+ "kcap-pages": {
44
44
  "command": "kcap",
45
- "args": ["mcp", "artefacts"],
45
+ "args": ["mcp", "pages"],
46
46
  "cwd": "${CLAUDE_PROJECT_DIR}",
47
47
  "description": "Publish a self-contained HTML page — a plan, a report, a comparison — and get back a link to share. The page is sandboxed with no network access, so inline everything as data URIs. Private until you set visibility."
48
48
  },
package/kcap/README.md CHANGED
@@ -20,6 +20,8 @@ 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 |
24
+ | `get_connection` | The server URL and profile this MCP server resolved at start; no network call |
23
25
 
24
26
  Repo-aware: it resolves the cwd to a repo hash at startup, so `search_sessions` defaults to *this* repo.
25
27
 
@@ -68,20 +70,20 @@ Governed read-only SQL over the org's curated coding-agent analytics views (sess
68
70
 
69
71
  Repo-aware: defaults to the cwd's repo; pass `scope: "global"` for org-wide questions. Requires `kcap login` and a kcap-server new enough to expose the `/api/analytics` endpoints.
70
72
 
71
- ### `kcap-artefacts`
73
+ ### `kcap-pages`
72
74
 
73
75
  Publish a self-contained HTML page — a plan, a report, a comparison — and get back a link to share. The page is served under a sandbox with no network access, so every style, script and image has to be inlined as a data URI; an external URL renders as nothing.
74
76
 
75
77
  | Tool | Description |
76
78
  |------|-------------|
77
- | `publish_artefact` | Publish a page (`title`, and either `html` or a local `path`); optional `description`, `visibility`, `grants`, `session_ids`, `response_schema` to make it answerable, and `update_id` to revise an existing artefact without changing its URL |
78
- | `await_artefact_responses` | Block until people have answered — the human checkpoint. Returns on a respondent count, on a close, or on a timeout (which is not an error) |
79
- | `get_artefact_results` | Tallies and each person's current answer, without waiting |
80
- | `close_artefact_responses` | Freeze a version's answers; `closed: false` reopens and clears any deadline |
81
- | `list_my_artefacts` | The artefacts you can see — id, title, audience, latest version, URL |
82
- | `set_artefact_visibility` | Replace an artefact's audience (`none` / `org` / `scoped` + grants) |
79
+ | `publish_page` | Publish a page (`title`, and either `html` or a local `path`); optional `description`, `visibility`, `grants`, `session_ids`, `response_schema` to make it answerable, and `update_id` to revise an existing page without changing its URL |
80
+ | `await_page_responses` | Block until people have answered — the human checkpoint. Returns on a respondent count, on a close, or on a timeout (which is not an error) |
81
+ | `get_page_results` | Tallies and each person's current answer, without waiting |
82
+ | `close_page_responses` | Freeze a version's answers; `closed: false` reopens and clears any deadline |
83
+ | `list_my_pages` | The pages you can see — id, title, audience, latest version, URL |
84
+ | `set_page_visibility` | Replace a page's audience (`none` / `org` / `scoped` + grants) |
83
85
 
84
- An artefact is private to its owner until visibility says otherwise. The current session is cited automatically from `KCAP_SESSION_ID`, so a publish is attributed to the work that produced it.
86
+ A page is private to its owner until visibility says otherwise. The current session is cited automatically from `KCAP_SESSION_ID`, so a publish is attributed to the work that produced it.
85
87
 
86
88
  Declaring a `response_schema` turns the page into a form the server validates and tallies: fields of type `choice`, `multi`, `score` or `text`, plus a `results_mode` deciding what other viewers see — `owner` (default, only you), `aggregate` (tallies, no names or free text) or `named` (who said what). Who answered is always the authenticated viewer; there is no field for it to forge. Reading, version history and takedown stay in the web UI.
87
89
 
@@ -110,7 +112,7 @@ Each hook pipes its JSON payload through the `kcap` CLI, which enriches it with
110
112
  - `review-flows` / `kcap-review-flows` — Run structured, iterative spec/code review loops; the reviewer vendor is chosen independently of the driver (pass a lowercase token like `claude`/`codex`/`cursor`)
111
113
  - `agent-flows` / `kcap-agent-flows` — Run structured multi-participant agent flows (catalog `definition_id` or an inline `definition_yaml`), each participant declaring its own vendor/model
112
114
  - `work-items` / `kcap-work-items` — Declare a work item's breakdown (parent and parts) and its blocks / blocked-by dependencies, so Home renders its topology, and record the loose ends a session leaves unfinished
113
- - `guided-tour` / `kcap-guided-tour` — Onboarding tour: what Capacitor has recorded for your team, then per-use-case tutorials (evals, session recall, PR review, analytics)
115
+ - `guided-tour` / `kcap-guided-tour` — Onboarding tour: seven cards, one per reply (welcome, capture, investigate, collaborate, review, use, reuse), each a few questions to ask your agent
114
116
 
115
117
  In Claude they're invoked as `/kcap:recap`, `/kcap:errors`, `/kcap:guided-tour`, etc.
116
118
 
@@ -10,15 +10,6 @@
10
10
  "timeout": 5
11
11
  }
12
12
  ]
13
- },
14
- {
15
- "hooks": [
16
- {
17
- "type": "command",
18
- "command": "${CLAUDE_PLUGIN_ROOT}/hooks/persist-session-id.sh",
19
- "timeout": 3
20
- }
21
- ]
22
13
  }
23
14
  ],
24
15
  "SessionEnd": [
@@ -79,6 +70,16 @@
79
70
  "async": true
80
71
  }
81
72
  ]
73
+ },
74
+ {
75
+ "matcher": "Read",
76
+ "hooks": [
77
+ {
78
+ "type": "command",
79
+ "command": "kcap hook --claude --plan-read --no-update-check",
80
+ "timeout": 3
81
+ }
82
+ ]
82
83
  }
83
84
  ],
84
85
  "PostToolUseFailure": [
@@ -132,7 +133,7 @@
132
133
  "hooks": [
133
134
  {
134
135
  "type": "command",
135
- "command": "${CLAUDE_PLUGIN_ROOT}/hooks/set-title-prompt.sh",
136
+ "command": "kcap hook --claude --title-prompt --no-update-check",
136
137
  "timeout": 2
137
138
  }
138
139
  ]
@@ -1,25 +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. 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 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.
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 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.
43
41
 
44
42
  ## Choosing the flow definition
45
43
 
46
- 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`:
47
45
 
48
- - Spec or design document → `definition_id: "spec-review"` (built-in; same as `review-flows`' `spec-review` kind)
49
- - Code changes or a pull request → `definition_id: "code-review"` (built-in; same as `review-flows`' `code-review` kind)
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. **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.
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
- | `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. |
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 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
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