@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 +26 -144
- package/bin/resolve.js +2 -7
- package/kcap/.claude-plugin/plugin.json +1 -1
- package/kcap/.codex-mcp.json +2 -2
- package/kcap/.mcp.json +2 -2
- package/kcap/README.md +11 -9
- package/kcap/hooks/hooks.json +11 -10
- package/kcap/skills/agent-flows/SKILL.md +36 -25
- package/kcap/skills/eval-watch/SKILL.md +112 -140
- package/kcap/skills/guided-tour/SKILL.md +258 -470
- package/kcap/skills/recap/SKILL.md +5 -2
- package/kcap/skills/review-flows/SKILL.md +9 -4
- package/kcap/skills/start-agents/SKILL.md +27 -7
- package/kcap/skills/work-items/SKILL.md +54 -22
- package/package.json +9 -9
- package/kcap/hooks/persist-session-id.sh +0 -11
- package/kcap/hooks/set-title-prompt.sh +0 -36
- package/kcap/skills/suggest-review-flow/SKILL.md +0 -94
package/bin/refresh.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// Refreshes kcap's user-scope coding-agent installs
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// Refreshes kcap's user-scope coding-agent installs after an install or upgrade, by running
|
|
2
|
+
// `kcap refresh` — the native binary owns the refresh list and the Claude plugin's .mcp.json patch,
|
|
3
|
+
// so every installer (npm, the install scripts, a script install's `kcap update`) runs the same one.
|
|
4
4
|
//
|
|
5
5
|
// Shared by:
|
|
6
6
|
// - postinstall.js — runs after `npm install -g @kurrent/kcap` (incl. upgrades),
|
|
@@ -10,152 +10,34 @@
|
|
|
10
10
|
//
|
|
11
11
|
// This file must never require kcap.js: during `kcap update`, runUpdate executes
|
|
12
12
|
// before kcap.js's final module.exports assignment, so it would observe partial
|
|
13
|
-
// exports.
|
|
13
|
+
// exports.
|
|
14
14
|
|
|
15
15
|
const { spawnSync } = require("child_process");
|
|
16
|
-
const path = require("path");
|
|
17
|
-
const fs = require("fs");
|
|
18
16
|
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
// opted in (marker file present OR pre-marker install detected). A vendor entry
|
|
22
|
-
// also refreshes the shared ~/.agents/skills tree, but only tops up one that is
|
|
23
|
-
// already there: `plugin remove --skills` must survive an upgrade. The daemon
|
|
24
|
-
// entry needs no marker: it acts only on service units that are already installed.
|
|
25
|
-
const REFRESHES = [
|
|
26
|
-
["plugin", "install", "--skills", "--if-installed"],
|
|
27
|
-
["plugin", "install", "--codex", "--if-installed"],
|
|
28
|
-
["plugin", "install", "--cursor", "--if-installed"],
|
|
29
|
-
["plugin", "install", "--copilot", "--if-installed"],
|
|
30
|
-
["plugin", "install", "--pi", "--if-installed"], // Pi extension (~/.pi/agent/extensions/kcap.ts)
|
|
31
|
-
["plugin", "install", "--opencode", "--if-installed"], // OpenCode plugin (~/.config/opencode/plugins/kcap.ts)
|
|
32
|
-
["plugin", "install", "--gemini", "--if-installed"], // Gemini hooks/MCP/instructions (~/.gemini)
|
|
33
|
-
["plugin", "install", "--kiro", "--if-installed"], // Kiro agent hooks (~/.kiro/agents/kcap.json)
|
|
34
|
-
["plugin", "install", "--antigravity", "--if-installed"], // Antigravity hooks (~/.gemini/config/plugins/kcap)
|
|
35
|
-
["plugin", "install", "--if-installed"], // Claude
|
|
36
|
-
["daemon", "service", "refresh"],
|
|
37
|
-
];
|
|
17
|
+
// Above the binary's own worst case: eleven steps, each bounded at 60s.
|
|
18
|
+
const REFRESH_TIMEOUT_MS = 15 * 60_000;
|
|
38
19
|
|
|
39
|
-
// Runs
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
function runRefreshes(launcherPath) {
|
|
44
|
-
// Point the shipped Claude plugin's MCP entries at the native binary. Runs
|
|
45
|
-
// here because runRefreshes fires at exactly the two moments the plugin dir
|
|
46
|
-
// has just been (re)written by npm: postinstall and `kcap update`.
|
|
47
|
-
patchPluginMcpConfig(launcherPath);
|
|
48
|
-
|
|
49
|
-
for (const argv of REFRESHES) {
|
|
50
|
-
try {
|
|
51
|
-
spawnSync(process.execPath, [launcherPath, ...argv], {
|
|
52
|
-
stdio: "ignore",
|
|
53
|
-
env: process.env,
|
|
54
|
-
// Hard ceiling so a stalled child can never hang the caller.
|
|
55
|
-
timeout: 60_000,
|
|
56
|
-
killSignal: "SIGKILL",
|
|
57
|
-
windowsHide: true,
|
|
58
|
-
});
|
|
59
|
-
} catch {
|
|
60
|
-
// Never fail the caller.
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// ── Claude plugin .mcp.json patch ───────────────────────────────────────────
|
|
66
|
-
//
|
|
67
|
-
// The plugin ships `"command": "kcap"`, which resolves to the node wrapper —
|
|
68
|
-
// one resident Node runtime per MCP server per open Claude session (~25 MB
|
|
69
|
-
// idle each). Rewriting the command to the resolved native binary makes Claude
|
|
70
|
-
// spawn the binary directly. Best-effort: on any failure the shipped value
|
|
71
|
-
// stays in place, which still works via the wrapper.
|
|
72
|
-
|
|
73
|
-
// The servers shipped in the plugin's .mcp.json, keyed by canonical
|
|
74
|
-
// `["mcp", <suffix>]` args. Only these exact name/args pairs are patched —
|
|
75
|
-
// anything else in the file is preserved verbatim.
|
|
76
|
-
const PLUGIN_MCP_SERVERS = {
|
|
77
|
-
"kcap-review": "review",
|
|
78
|
-
"kcap-sessions": "sessions",
|
|
79
|
-
"kcap-flows": "flows",
|
|
80
|
-
"kcap-memory": "memory",
|
|
81
|
-
"kcap-workitems": "workitems",
|
|
82
|
-
"kcap-plans": "plans",
|
|
83
|
-
"kcap-artefacts": "artefacts",
|
|
84
|
-
"kcap-analytics": "analytics",
|
|
85
|
-
"kcap-knowledge": "knowledge",
|
|
86
|
-
"kcap-handoff": "handoff",
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
// A command this patcher may rewrite: the shipped literal "kcap", or an
|
|
90
|
-
// absolute path whose basename is the kcap binary (a previous patch that has
|
|
91
|
-
// gone stale after an npm re-layout). Handles both path flavors so a stale
|
|
92
|
-
// Windows path is still recognized. Anything else is a customization → keep.
|
|
93
|
-
function isPatchableKcapCommand(command) {
|
|
94
|
-
if (command === "kcap") return true;
|
|
95
|
-
if (typeof command !== "string") return false;
|
|
96
|
-
if (!path.posix.isAbsolute(command) && !path.win32.isAbsolute(command)) return false;
|
|
97
|
-
const base = command.split(/[\\/]/).pop().toLowerCase();
|
|
98
|
-
return base === "kcap" || base === "kcap.exe";
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Pure: rewrites in place the canonical plugin entries of `cfg` whose command
|
|
102
|
-
// is patchable, returning whether anything changed. Throws on a shape that
|
|
103
|
-
// isn't the plugin config (caller turns that into the single warning).
|
|
104
|
-
function patchPluginMcpServers(cfg, binaryPath) {
|
|
105
|
-
if (!cfg || typeof cfg !== "object" || Array.isArray(cfg)) {
|
|
106
|
-
throw new Error("config is not an object");
|
|
107
|
-
}
|
|
108
|
-
const servers = cfg.mcpServers;
|
|
109
|
-
if (!servers || typeof servers !== "object" || Array.isArray(servers)) {
|
|
110
|
-
throw new Error("mcpServers is not an object");
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
let changed = false;
|
|
114
|
-
for (const [name, suffix] of Object.entries(PLUGIN_MCP_SERVERS)) {
|
|
115
|
-
const entry = servers[name];
|
|
116
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
117
|
-
if (!Array.isArray(entry.args) || entry.args.length !== 2 ||
|
|
118
|
-
entry.args[0] !== "mcp" || entry.args[1] !== suffix) continue; // customized args → keep
|
|
119
|
-
if (!isPatchableKcapCommand(entry.command)) continue; // customized command → keep
|
|
120
|
-
if (entry.command === binaryPath) continue; // already current
|
|
121
|
-
entry.command = binaryPath;
|
|
122
|
-
changed = true;
|
|
123
|
-
}
|
|
124
|
-
return changed;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Rewrites the plugin's shipped .mcp.json (a sibling `kcap/` dir of the
|
|
128
|
-
// launcher's `bin/`) so Claude spawns the native binary directly. Validates
|
|
129
|
-
// before writing, writes a sibling temp file, then renames atomically — the
|
|
130
|
-
// original survives any pre-rename failure. Never throws; on failure it emits
|
|
131
|
-
// ONE concise warning and leaves the shipped `"command": "kcap"` in place.
|
|
132
|
-
// `binaryPath` is a test seam; real callers let it resolve.
|
|
133
|
-
function patchPluginMcpConfig(launcherPath, binaryPath) {
|
|
134
|
-
let mcpJsonPath;
|
|
20
|
+
// Runs `kcap refresh` through the given launcher (an absolute path to kcap.js), so the NEW
|
|
21
|
+
// launcher and the NEW binary run it after an upgrade. Never throws and never fails the caller:
|
|
22
|
+
// a failed refresh must never break `npm install` or report `kcap update` as failed. Its stderr
|
|
23
|
+
// (which steps failed, a plugin patch that could not be written) is passed on through `warn`.
|
|
24
|
+
function runRefreshes(launcherPath, warn = console.warn) {
|
|
135
25
|
try {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
try { fs.unlinkSync(tmp); } catch {}
|
|
151
|
-
throw e;
|
|
152
|
-
}
|
|
153
|
-
} catch (e) {
|
|
154
|
-
console.warn(
|
|
155
|
-
`kcap: could not point the Claude plugin MCP entries at the native binary` +
|
|
156
|
-
` (${e && e.message ? e.message : e}); they will keep launching via the node wrapper.`,
|
|
157
|
-
);
|
|
26
|
+
const result = spawnSync(process.execPath, [launcherPath, "refresh"], {
|
|
27
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
28
|
+
encoding: "utf8",
|
|
29
|
+
env: process.env,
|
|
30
|
+
timeout: REFRESH_TIMEOUT_MS,
|
|
31
|
+
killSignal: "SIGKILL",
|
|
32
|
+
windowsHide: true,
|
|
33
|
+
});
|
|
34
|
+
const stderr = (result.stderr || "").trim();
|
|
35
|
+
if (stderr) warn(stderr);
|
|
36
|
+
if (result.status !== 0)
|
|
37
|
+
warn("kcap: some agent integrations were not refreshed; run `kcap refresh` to retry.");
|
|
38
|
+
} catch {
|
|
39
|
+
// Never fail the caller.
|
|
158
40
|
}
|
|
159
41
|
}
|
|
160
42
|
|
|
161
|
-
module.exports = { runRefreshes
|
|
43
|
+
module.exports = { runRefreshes };
|
package/bin/resolve.js
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
// Side-effect-free platform/native-binary resolution
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// This lives in its OWN module — refresh.js must never require kcap.js: during
|
|
5
|
-
// `kcap update`, runUpdate executes BEFORE kcap.js's final module.exports
|
|
6
|
-
// assignment, so a refresh.js → kcap.js require would observe partial exports
|
|
7
|
-
// exactly on that path. Requiring this module has no side effects.
|
|
1
|
+
// Side-effect-free platform/native-binary resolution for kcap.js (the launcher).
|
|
2
|
+
// Requiring this module has no side effects.
|
|
8
3
|
|
|
9
4
|
const path = require("path");
|
|
10
5
|
const fs = require("fs");
|
package/kcap/.codex-mcp.json
CHANGED
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-
|
|
43
|
+
"kcap-pages": {
|
|
44
44
|
"command": "kcap",
|
|
45
|
-
"args": ["mcp", "
|
|
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-
|
|
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
|
-
| `
|
|
78
|
-
| `
|
|
79
|
-
| `
|
|
80
|
-
| `
|
|
81
|
-
| `
|
|
82
|
-
| `
|
|
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
|
-
|
|
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:
|
|
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
|
|
package/kcap/hooks/hooks.json
CHANGED
|
@@ -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": "
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
work directly instead. To start a hosted agent that works on its own, use
|
|
17
|
-
`start-agents`.
|
|
4
|
+
Use this skill to drive a structured agent *flow*: a separate hosted
|
|
5
|
+
participant agent runs a definition from the server's flow catalogue and
|
|
6
|
+
iterates with you until sign-off. Use it when the user names a flow or
|
|
7
|
+
definition id ("run the code-review flow", "start a flow", "use flow
|
|
8
|
+
definition X"), when the user accepts a flow you offered, or when you are
|
|
9
|
+
about to offer one listed under "Flows you may offer" in your session
|
|
10
|
+
context because its when-to-use applies. Before starting a flow, call
|
|
11
|
+
get_flow_definition and follow its guide. Do NOT use this skill (and do NOT
|
|
12
|
+
call the flows MCP tools) for an ordinary request such as "review my PR",
|
|
13
|
+
"do X for me", or "check this over" where the user wants you to do the work
|
|
14
|
+
yourself — do it directly instead. To start a hosted agent that works on its
|
|
15
|
+
own, use `start-agents`.
|
|
18
16
|
---
|
|
19
17
|
|
|
20
18
|
# Agent Flows
|
|
21
19
|
|
|
22
|
-
Use the `kcap mcp flows` MCP tools (`list_flow_definitions`, `start_flow`, `send_to_participant`, `get_flow_status`, `close_flow`) to run a structured agent **flow**: your work is handed to a **separate, hosted participant agent** driven by a flow definition from the server's catalog, which returns a result (kind `findings` with the participant's result text, or `clean`); you address a `findings` result and keep iterating until the clean signal. This is a deliberate, heavier workflow — use it
|
|
20
|
+
Use the `kcap mcp flows` MCP tools (`list_flow_definitions`, `get_flow_definition`, `start_flow`, `send_to_participant`, `get_flow_status`, `close_flow`) to run a structured agent **flow**: your work is handed to a **separate, hosted participant agent** driven by a flow definition from the server's catalog, which returns a result (kind `findings` with the participant's result text, or `clean`); you address a `findings` result and keep iterating until the clean signal. This is a deliberate, heavier workflow — use it when the user asks for a flow or accepts one you offered, never on your own initiative.
|
|
23
21
|
|
|
24
22
|
## Long rounds are normal
|
|
25
23
|
|
|
@@ -39,15 +37,14 @@ and end the reviewer turn. The hosted-reviewer contract wins over driver-looking
|
|
|
39
37
|
|
|
40
38
|
These tools do **not** perform the work themselves — they hand it off to a separate hosted participant agent running a named flow definition. If the user simply asked *you* to do something in a normal session — e.g. "review my PR", "review this diff", "check this spec", "do X" — just do it yourself and report the result directly. Do **NOT** call `start_flow` / `send_to_participant` for an ordinary request; that would spin up a hosted agent the user did not ask for.
|
|
41
39
|
|
|
42
|
-
Only start a flow when the user explicitly asks for
|
|
40
|
+
Only start a flow when the user explicitly asks for one — e.g. "start a flow", "run the code-review flow", "use flow definition X", or "re-review after I address the findings" via a flow — or accepts a flow you offered. Offer a flow only when your session context lists it under **Flows you may offer** and its when-to-use applies to what just happened; ask, and never start it before the user says yes. Skip the offer when the user asked you to do the work yourself, or while you are mid-task.
|
|
43
41
|
|
|
44
42
|
## Choosing the flow definition
|
|
45
43
|
|
|
46
|
-
Once the user has
|
|
44
|
+
Once the user has asked for a flow or accepted one you offered (see above), pick the `definition_id`:
|
|
47
45
|
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
- Anything else → the definition id the user named, or one from `list_flow_definitions` (read-only), which lists every definition this server can start — operator-published ones included — with its version, description, participant roles and their authored vendor and model, and whether it is single- or multi-participant. Call it whenever the user has not named a definition, or named one you have not seen listed: a definition it does not list is disabled, deleted or unknown, and `start_flow` will refuse it. If several fit, ask the user rather than guessing. A server that answers that it cannot list definitions only predates the tool — the two built-ins and any id the user names still work.
|
|
46
|
+
- The flow the user named, or the one you offered and they accepted.
|
|
47
|
+
- If the user has not named one → choose from `list_flow_definitions` (read-only), which lists every definition this server can start — operator-published ones included — with its version, description, participant roles and their authored vendor and model, and whether it is single- or multi-participant. Call it whenever the user has not named a definition, or named one you have not seen listed: a definition it does not list is disabled, deleted or unknown, and `start_flow` will refuse it. If several fit, ask the user rather than guessing. A server that answers that it cannot list definitions only predates the tool — the two built-ins and any id the user names still work.
|
|
51
48
|
|
|
52
49
|
For the reserved `spec-review` and `code-review` aliases, reviewer-vendor language is role-bound:
|
|
53
50
|
pass the one vendor explicitly named as the reviewer, ignore driver-harness mentions, honor
|
|
@@ -88,6 +85,10 @@ vendor supports this: the daemon must advertise a runtime model resolver for the
|
|
|
88
85
|
(Claude and Codex today; other vendors keep vendor-only overrides with no model choice) or the
|
|
89
86
|
server rejects the override outright.
|
|
90
87
|
|
|
88
|
+
## Read the flow's guide first
|
|
89
|
+
|
|
90
|
+
Before a catalogue start (`definition_id`), call `get_flow_definition(definition_id)`. The guide is written by whoever published the flow: what to put in `context`, which target to name, how to iterate on its results and when to close. Where it differs from the generic rules below, follow the guide. A server that does not publish guides says so; then work from the definition's description and the rules below. A flow started with an inline `definition_yaml` has no catalogue id and no guide: drive it by the generic rules and its own YAML.
|
|
91
|
+
|
|
91
92
|
## Composing a dynamic flow
|
|
92
93
|
|
|
93
94
|
If nothing `list_flow_definitions` shows fits — no `definition_id` covers the roles or workflow you need — compose one inline instead: pass `definition_yaml` to `start_flow` in place of `definition_id`. Provide exactly one of the two, never both. (`start_review_flow` / `submit_review_round` stay catalog-only — this only applies to the generic `start_flow`.)
|
|
@@ -147,7 +148,7 @@ After applying the role-surface safety gate, if `start_flow` / `send_to_particip
|
|
|
147
148
|
5. **If participant output is unclear or requires user input**, pause and ask the user before proceeding.
|
|
148
149
|
6. **Never start a nested flow.** If you are the hosted participant (see above), do not call these tools yourself.
|
|
149
150
|
7. **Address each role independently.** A flow definition declares one or more participant roles in its `participants` map (single-participant definitions use `reviewer`). A multi-participant `start_flow` returns no round — nothing has launched yet. Call `send_to_participant(flow_run_id, participant=<role>, message=…)` naming the role you want to address; its first message launches that role's agent lazily. Only one round is in flight per role at a time — sending to a role that's still working on a round gets a `409` naming the busy round — but every OTHER role stays addressable in the meantime. Sending an unknown role is rejected by the server, which names the valid roles in its error.
|
|
150
|
-
8. **
|
|
151
|
+
8. **Ask the participant only for what the flow's guide allows.** If the guide says CI covers tests, do not ask the participant to run them; participant feedback is on what the flow exists to judge.
|
|
151
152
|
9. **State where your changes live.** The participant's worktree is mirrored from **this session's project directory**, not from the directory you are working in, and no tool parameter can redirect it. So if you changed directory, are a subagent in another checkout, or the changeset lives in another worktree/repo/machine, the participant will NOT see it: say so in `context`/`message`, give it an explicit commit range (never `git diff origin/main...HEAD`), and inline the diffs — or pass `mode: "context-only"` to make your context the sole source of truth. The participant flags referenced changes it cannot find; incomplete context wastes a full round.
|
|
152
153
|
|
|
153
154
|
## Pending messages
|
|
@@ -170,10 +171,17 @@ The server enforces per-run budgets; watch for these in tool error responses:
|
|
|
170
171
|
|
|
171
172
|
## Workflow
|
|
172
173
|
|
|
174
|
+
A catalogue flow (`definition_id`) starts with its guide; an inline `definition_yaml` flow skips this step:
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
get_flow_definition(definition_id)
|
|
178
|
+
→ read the driver guide; prepare the context it asks for
|
|
179
|
+
```
|
|
180
|
+
|
|
173
181
|
Single-participant definitions start eagerly — round 1 runs as part of `start_flow`:
|
|
174
182
|
|
|
175
183
|
```
|
|
176
|
-
start_flow(definition_id, target_kind, target_ref, target_title, context)
|
|
184
|
+
start_flow(definition_id, target_kind, target_ref, target_title, session_title, context)
|
|
177
185
|
→ participant returns a result: kind findings (with the result text) | kind clean
|
|
178
186
|
|
|
179
187
|
if clean:
|
|
@@ -192,7 +200,7 @@ if findings:
|
|
|
192
200
|
Multi-participant definitions start round-less — you address each role yourself, and the run is clean only in aggregate:
|
|
193
201
|
|
|
194
202
|
```
|
|
195
|
-
start_flow(definition_id, target_kind, target_ref, target_title, context)
|
|
203
|
+
start_flow(definition_id, target_kind, target_ref, target_title, session_title, context)
|
|
196
204
|
→ no round yet — roles have not launched
|
|
197
205
|
|
|
198
206
|
send_to_participant(flow_run_id, participant="reviewer", message=…)
|
|
@@ -218,7 +226,8 @@ report completion to user
|
|
|
218
226
|
| Tool | Required args | Optional args | When to call |
|
|
219
227
|
|---|---|---|---|
|
|
220
228
|
| `list_flow_definitions` | — | — | Before `start_flow`, whenever the user has not named a definition or named one you have not seen listed. Read-only: returns each runnable definition's id, version, description, whether it is single- or multi-participant, and its participants' role, authored vendor and model. A `server_catching_up` error is retryable — do not read it as an empty catalog. |
|
|
221
|
-
| `
|
|
229
|
+
| `get_flow_definition` | `definition_id` | — | Before every catalogue (`definition_id`) `start_flow`. Read-only: returns the definition's participants and when to use it, then its authored driver guide (what to submit, how to iterate, when to close). An unknown, disabled or deleted id is an error; an older server reports that it publishes no guides. |
|
|
230
|
+
| `start_flow` | Exactly one of `definition_id` (catalog id, e.g. `spec-review`, `code-review`, or a custom catalog id) or `definition_yaml` (inline dynamic definition — see "Composing a dynamic flow"); plus `target_kind` (what is being worked on: `spec`, `code`, `pr`, `branch`, `file`, etc.), `target_ref` (a path, branch name, or PR URL/number that identifies the target), `target_title` (short human-readable title), `session_title` (the participant session's title: a short phrase naming this piece of work, specific enough to tell it apart from other sessions — it replaces the definition's generic opening instruction as the name), `context` (background context: what to focus on, constraints, definition of done) | `vendor` (reserved aliases only — explicit reviewer vendor; omit to use the definition's authored vendor, or your saved `flows.reviewer_vendor` preference if it declares none), `model` (reserved aliases only — explicit reviewer model override; REQUIRES `vendor`, rejected on dynamic/multi-participant starts), `instructions`, `mode` (`context-only` — optional; by default the participant's worktree is mirrored from THIS SESSION's project directory, not from the directory you are working in. Pass `context-only` to opt out and treat the submitted context as authoritative) | Once, at the start of a flow task. |
|
|
222
231
|
| `send_to_participant` | `flow_run_id`, `participant` (role name declared in the flow definition's `participants` map; single-participant definitions use `reviewer` — an unknown role is rejected, naming the valid ones), `message` | `instructions`, `async` (defaults to `true`) | After addressing a non-clean result for that role, or to launch a role for the first time. Pass the same `flow_run_id`, the role's name, and the updated message. |
|
|
223
232
|
| `get_flow_status` | — | `flow_run_id` (omit to read the newest open flow this session started, or on a harness without a session identity the newest one started from this workspace; several open flows are listed instead), `session_id` (look up another session's flows; defaults to this session), `wait` (`true`/`false`, defaults to `false`) — when `true`, blocks until the round is terminal or roughly 3.5 minutes pass, instead of returning the current snapshot immediately | Poll or check the current status of a flow run (running, waiting, completed, failed). Use `wait: true` to ride out a long round instead of polling repeatedly yourself, and omit `flow_run_id` to recover a flow whose id you never received or lost. |
|
|
224
233
|
| `close_flow` | `flow_run_id` | — | Only after the definition's clean signal — or when abandoning the task early; the run otherwise stays open until closed. |
|
|
@@ -226,13 +235,14 @@ report completion to user
|
|
|
226
235
|
## Example (custom definition)
|
|
227
236
|
|
|
228
237
|
```
|
|
229
|
-
# Step 1 — start (all
|
|
238
|
+
# Step 1 — start (all six args required; the participant sees a mirror of THIS SESSION's
|
|
230
239
|
# project directory, not of the directory you are working in — pass mode="context-only" to opt out)
|
|
231
240
|
start_flow(
|
|
232
241
|
definition_id="code-review",
|
|
233
242
|
target_kind="branch",
|
|
234
243
|
target_ref="feature/add-null-check",
|
|
235
244
|
target_title="Add null check on user input",
|
|
245
|
+
session_title="Review the null check on user input",
|
|
236
246
|
context="Review the diff on this branch for correctness and adherence to project conventions."
|
|
237
247
|
)
|
|
238
248
|
# → returns flow_run_id, e.g. "flow_abc123"
|
|
@@ -261,6 +271,7 @@ start_flow(
|
|
|
261
271
|
target_kind="branch",
|
|
262
272
|
target_ref="feature/add-null-check",
|
|
263
273
|
target_title="Add null check on user input",
|
|
274
|
+
session_title="Review and test the null check on user input",
|
|
264
275
|
context="Review the diff on this branch and write/run tests for the new code path."
|
|
265
276
|
)
|
|
266
277
|
# → returns flow_run_id, e.g. "flow_xyz789"; no round in the response
|