@gempack/squad-mcp 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +2 -1
- package/CHANGELOG.md +146 -2
- package/INSTALL.md +422 -0
- package/README.md +44 -10
- package/agents/Senior-Dev-Reviewer.md +550 -46
- package/agents/Skill-Squad-Dev.md +30 -3
- package/agents/Skill-Squad-Review.md +70 -0
- package/commands/brainstorm.md +21 -0
- package/commands/commit-suggest.md +12 -0
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/resources/agent-loader.d.ts +13 -1
- package/dist/resources/agent-loader.js +197 -28
- package/dist/resources/agent-loader.js.map +1 -1
- package/dist/tools/agents.js +4 -1
- package/dist/tools/agents.js.map +1 -1
- package/dist/util/override-allowlist.d.ts +63 -0
- package/dist/util/override-allowlist.js +191 -0
- package/dist/util/override-allowlist.js.map +1 -0
- package/dist/util/path-internal.d.ts +6 -0
- package/dist/util/path-internal.js +27 -0
- package/dist/util/path-internal.js.map +1 -0
- package/dist/util/path-safety.js +0 -0
- package/dist/util/path-safety.js.map +1 -1
- package/package.json +2 -1
- package/skills/brainstorm/SKILL.md +284 -0
- package/skills/commit-suggest/SKILL.md +255 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import { SquadError } from '../errors.js';
|
|
5
|
+
import { rejectIfMalformed, realpathOrSelf } from './path-internal.js';
|
|
6
|
+
let allowlistCache = null;
|
|
7
|
+
/**
|
|
8
|
+
* Test-only: clears the memoized allowlist so env-var changes take effect.
|
|
9
|
+
* Production code should never call this.
|
|
10
|
+
*/
|
|
11
|
+
export function __resetOverrideAllowlistCache() {
|
|
12
|
+
allowlistCache = null;
|
|
13
|
+
}
|
|
14
|
+
function isUnsafeOverrideEnabled() {
|
|
15
|
+
return process.env.SQUAD_AGENTS_ALLOW_UNSAFE === '1';
|
|
16
|
+
}
|
|
17
|
+
function isUncOrDeviceNamespace(absolute) {
|
|
18
|
+
if (process.platform !== 'win32')
|
|
19
|
+
return false;
|
|
20
|
+
if (absolute.startsWith('\\\\?\\'))
|
|
21
|
+
return true;
|
|
22
|
+
if (absolute.startsWith('\\\\.\\'))
|
|
23
|
+
return true;
|
|
24
|
+
if (absolute.startsWith('\\\\'))
|
|
25
|
+
return true;
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
async function buildAllowlist() {
|
|
29
|
+
if (allowlistCache !== null)
|
|
30
|
+
return allowlistCache;
|
|
31
|
+
const roots = [];
|
|
32
|
+
const seen = new Set();
|
|
33
|
+
const candidates = [
|
|
34
|
+
{ source: 'home', raw: os.homedir() },
|
|
35
|
+
{ source: 'cwd', raw: process.cwd() },
|
|
36
|
+
];
|
|
37
|
+
if (process.platform === 'win32') {
|
|
38
|
+
candidates.push({ source: 'appdata', raw: process.env.APPDATA });
|
|
39
|
+
candidates.push({ source: 'localappdata', raw: process.env.LOCALAPPDATA });
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
candidates.push({ source: 'xdg_config_home', raw: process.env.XDG_CONFIG_HOME });
|
|
43
|
+
}
|
|
44
|
+
for (const c of candidates) {
|
|
45
|
+
if (!c.raw)
|
|
46
|
+
continue;
|
|
47
|
+
if (!path.isAbsolute(c.raw))
|
|
48
|
+
continue;
|
|
49
|
+
try {
|
|
50
|
+
rejectIfMalformed(c.raw);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// hostile env var (e.g. APPDATA injected with NUL) — silently skip from allowlist
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (isUncOrDeviceNamespace(c.raw))
|
|
57
|
+
continue;
|
|
58
|
+
const lexical = path.normalize(c.raw);
|
|
59
|
+
const real = await realpathOrSelf(lexical);
|
|
60
|
+
if (seen.has(real))
|
|
61
|
+
continue;
|
|
62
|
+
seen.add(real);
|
|
63
|
+
roots.push({ source: c.source, lexical, real });
|
|
64
|
+
}
|
|
65
|
+
allowlistCache = roots;
|
|
66
|
+
return roots;
|
|
67
|
+
}
|
|
68
|
+
function isInsideRoot(candidate, root) {
|
|
69
|
+
if (candidate === root)
|
|
70
|
+
return true;
|
|
71
|
+
const rel = path.relative(root, candidate);
|
|
72
|
+
if (rel === '' || rel === '.')
|
|
73
|
+
return true;
|
|
74
|
+
if (path.isAbsolute(rel))
|
|
75
|
+
return false;
|
|
76
|
+
if (rel === '..')
|
|
77
|
+
return false;
|
|
78
|
+
if (rel.startsWith('..' + path.sep))
|
|
79
|
+
return false;
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
function findAllowlistMatch(candidateLexical, candidateReal, roots) {
|
|
83
|
+
// Lexical AND realpath both must be inside the same allowlist entry.
|
|
84
|
+
// (Either alone is a known bypass: a symlinked-out lexical-allowed path,
|
|
85
|
+
// or a realpath-allowed path that lexically points elsewhere.)
|
|
86
|
+
for (const r of roots) {
|
|
87
|
+
if (isInsideRoot(candidateLexical, r.lexical) && isInsideRoot(candidateReal, r.real)) {
|
|
88
|
+
return r;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Validate an override directory.
|
|
95
|
+
*
|
|
96
|
+
* Returns the resolved (realpath) directory on success. Throws `OVERRIDE_REJECTED`
|
|
97
|
+
* for policy violations (UNC, malformed, not absolute, outside allowlist, symlink
|
|
98
|
+
* escape) UNLESS `SQUAD_AGENTS_ALLOW_UNSAFE=1` is set, in which case the violation
|
|
99
|
+
* is bypassed (still rejects malformed inputs hard — those are not policy choices).
|
|
100
|
+
*/
|
|
101
|
+
export async function validateOverrideDir(rawDir) {
|
|
102
|
+
// Hard rejections — never bypassed by the escape hatch.
|
|
103
|
+
try {
|
|
104
|
+
rejectIfMalformed(rawDir);
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
return { ok: false, reason: 'malformed', rejectedPath: rawDir };
|
|
108
|
+
}
|
|
109
|
+
if (!path.isAbsolute(rawDir)) {
|
|
110
|
+
return { ok: false, reason: 'not_absolute', rejectedPath: rawDir };
|
|
111
|
+
}
|
|
112
|
+
if (isUncOrDeviceNamespace(rawDir)) {
|
|
113
|
+
return { ok: false, reason: 'unc_or_device_namespace', rejectedPath: rawDir };
|
|
114
|
+
}
|
|
115
|
+
const lexical = path.normalize(rawDir);
|
|
116
|
+
const real = await realpathOrSelf(lexical);
|
|
117
|
+
const unsafe = isUnsafeOverrideEnabled();
|
|
118
|
+
const roots = await buildAllowlist();
|
|
119
|
+
const match = findAllowlistMatch(lexical, real, roots);
|
|
120
|
+
if (match) {
|
|
121
|
+
return { ok: true, resolvedPath: real, allowlistMatch: match.source, unsafeOverride: false };
|
|
122
|
+
}
|
|
123
|
+
// Distinguish lexical-only escape (likely symlink) from outright outside-allowlist.
|
|
124
|
+
// If lexical matches some root but realpath does not, the user did `ln -s /tmp/x ~/.squad`.
|
|
125
|
+
let lexicalMatchExists = false;
|
|
126
|
+
for (const r of roots) {
|
|
127
|
+
if (isInsideRoot(lexical, r.lexical)) {
|
|
128
|
+
lexicalMatchExists = true;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const reason = lexicalMatchExists ? 'symlink_escape' : 'outside_allowlist';
|
|
133
|
+
if (unsafe) {
|
|
134
|
+
return { ok: true, resolvedPath: real, allowlistMatch: 'unsafe_override', unsafeOverride: true };
|
|
135
|
+
}
|
|
136
|
+
return { ok: false, reason, rejectedPath: rawDir };
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Convert a `ValidationFail` into a structured `OVERRIDE_REJECTED` error.
|
|
140
|
+
* Caller decides whether to throw or downgrade to a warn-and-fallback.
|
|
141
|
+
*/
|
|
142
|
+
export function rejectionToError(fail, allowlistSize) {
|
|
143
|
+
return new SquadError('OVERRIDE_REJECTED', `override directory rejected: ${fail.reason}`, {
|
|
144
|
+
reason: fail.reason,
|
|
145
|
+
path: fail.rejectedPath,
|
|
146
|
+
allowlist_size: allowlistSize,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
export async function getAllowlistSize() {
|
|
150
|
+
const roots = await buildAllowlist();
|
|
151
|
+
return roots.length;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Validate that a candidate file path inside a previously-validated override
|
|
155
|
+
* directory does not escape (after symlink resolution).
|
|
156
|
+
*
|
|
157
|
+
* Returns the file's realpath on success, or `null` if the file does not exist
|
|
158
|
+
* or escapes the directory. Per-file escape is NOT a policy-level error — the
|
|
159
|
+
* caller falls back to embedded for that file only and continues.
|
|
160
|
+
*/
|
|
161
|
+
export async function validateOverrideFile(validatedDirReal, fileName) {
|
|
162
|
+
try {
|
|
163
|
+
rejectIfMalformed(fileName);
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
// Lexical: file name must not contain traversal segments.
|
|
169
|
+
const normalized = path.normalize(fileName);
|
|
170
|
+
if (path.isAbsolute(normalized))
|
|
171
|
+
return null;
|
|
172
|
+
if (normalized === '..' || normalized.startsWith('..' + path.sep) || normalized.includes(path.sep + '..' + path.sep)) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
const candidate = path.resolve(validatedDirReal, normalized);
|
|
176
|
+
// Lexical containment.
|
|
177
|
+
if (!isInsideRoot(candidate, validatedDirReal))
|
|
178
|
+
return null;
|
|
179
|
+
// Existence check before realpath.
|
|
180
|
+
try {
|
|
181
|
+
await fs.access(candidate);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
const real = await realpathOrSelf(candidate);
|
|
187
|
+
if (!isInsideRoot(real, validatedDirReal))
|
|
188
|
+
return null;
|
|
189
|
+
return real;
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=override-allowlist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"override-allowlist.js","sourceRoot":"","sources":["../../src/util/override-allowlist.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal helpers shared between path-safety.ts and override-allowlist.ts.
|
|
3
|
+
* Exported only for intra-`util/` reuse; do not import from outside src/util/.
|
|
4
|
+
*/
|
|
5
|
+
export declare function rejectIfMalformed(file: string): void;
|
|
6
|
+
export declare function realpathOrSelf(p: string): Promise<string>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import { SquadError } from '../errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* Internal helpers shared between path-safety.ts and override-allowlist.ts.
|
|
5
|
+
* Exported only for intra-`util/` reuse; do not import from outside src/util/.
|
|
6
|
+
*/
|
|
7
|
+
export function rejectIfMalformed(file) {
|
|
8
|
+
if (file.includes('\0')) {
|
|
9
|
+
throw new SquadError('PATH_INVALID', 'file path contains NUL byte', { file });
|
|
10
|
+
}
|
|
11
|
+
if (file.startsWith('~')) {
|
|
12
|
+
throw new SquadError('PATH_INVALID', 'file path starts with ~ (tilde expansion not supported)', { file });
|
|
13
|
+
}
|
|
14
|
+
const adsIndex = file.indexOf(':', 2);
|
|
15
|
+
if (adsIndex !== -1) {
|
|
16
|
+
throw new SquadError('PATH_INVALID', 'file path contains ADS marker (:) after drive letter', { file });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export async function realpathOrSelf(p) {
|
|
20
|
+
try {
|
|
21
|
+
return await fs.realpath(p);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return p;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=path-internal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-internal.js","sourceRoot":"","sources":["../../src/util/path-internal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C;;;GAGG;AAEH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,6BAA6B,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,yDAAyD,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5G,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACtC,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,sDAAsD,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACzG,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,CAAS;IAC5C,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
|
package/dist/util/path-safety.js
CHANGED
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-safety.js","sourceRoot":"","sources":["../../src/util/path-safety.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"path-safety.js","sourceRoot":"","sources":["../../src/util/path-safety.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEvE,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC;AAMhC,MAAM,UAAU,qBAAqB;IACnC,OAAO,EAAE,aAAa,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;AACtC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,aAAiC,EACjC,IAAY,EACZ,GAAoB;IAEpB,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAExB,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,UAAU,CAClB,yBAAyB,EACzB,4DAA4D,EAC5D,EAAE,IAAI,EAAE,CACT,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,iCAAiC,EAAE,EAAE,aAAa,EAAE,CAAC,CAAC;IAC7F,CAAC;IAED,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IACrD,IAAI,QAAQ,GAAG,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACrD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,QAAQ,GAAG,MAAM,cAAc,CAAC,cAAc,CAAC,CAAC;QAChD,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IAE5D,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACzD,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACjG,MAAM,IAAI,UAAU,CAAC,uBAAuB,EAAE,uCAAuC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACnG,CAAC;IAED,IAAI,eAAe,GAAG,KAAK,CAAC;IAC5B,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAC9B,eAAe,GAAG,IAAI,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,0DAA0D;IAC5D,CAAC;IAED,IAAI,eAAe,EAAE,CAAC;QACpB,MAAM,aAAa,GAAG,MAAM,cAAc,CAAC,YAAY,CAAC,CAAC;QACzD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QACvD,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACxF,MAAM,IAAI,UAAU,CAAC,uBAAuB,EAAE,8CAA8C,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1G,CAAC;QACD,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAOD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAe;IAC/C,IAAI,EAAE,CAAC;IACP,IAAI,CAAC;QACH,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACpC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QAC1D,OAAO;YACL,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;YACjD,SAAS,EAAE,SAAS,KAAK,SAAS;SACnC,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gempack/squad-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "MCP server for the squad-dev workflow: classification, risk scoring, agent selection, advisory orchestration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"skills",
|
|
48
48
|
".claude-plugin",
|
|
49
49
|
"README.md",
|
|
50
|
+
"INSTALL.md",
|
|
50
51
|
"LICENSE",
|
|
51
52
|
"NOTICE",
|
|
52
53
|
"CHANGELOG.md"
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: brainstorm
|
|
3
|
+
description: Collaborative brainstorm and research skill. Takes a problem, decision, or implementation topic; runs deep web research in parallel; spawns specialist agents for multi-domain perspectives; synthesizes findings into an options matrix with pros/cons/risks/sources and a recommendation. Output is a decision aid, NOT code. Use this BEFORE /squad to decide what to build; use /squad after to implement. Trigger when the user types /brainstorm or asks to "brainstorm", "research approaches", "explore options", "help me think through", "what does the industry use", or "best practices for".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: Brainstorm
|
|
7
|
+
|
|
8
|
+
## Objective
|
|
9
|
+
Help the user think through a problem, decision, or implementation idea by running parallel web research (market patterns, best practices, pitfalls, examples) and gathering specialist agent perspectives, then synthesizing the findings into a structured options matrix with a recommendation. This skill is exploratory — it does not write code, run tests, or modify the repo.
|
|
10
|
+
|
|
11
|
+
Position in the workflow:
|
|
12
|
+
- **`/brainstorm`** → decide what to build (this skill)
|
|
13
|
+
- **`/squad`** → implement what was decided
|
|
14
|
+
- **`/squad-review`** → review what was implemented
|
|
15
|
+
|
|
16
|
+
## Skill Name
|
|
17
|
+
`/brainstorm`
|
|
18
|
+
|
|
19
|
+
## Inviolable Rules
|
|
20
|
+
|
|
21
|
+
1. **No code implementation.** This skill produces a brainstorm report. It must not edit files, run scripts, run tests, or modify any persistent state.
|
|
22
|
+
2. **No `git commit`, `git push`, or any state-mutating git command.** Read-only git is fine (`git log`, `git status`, `git diff` for context).
|
|
23
|
+
3. **Cite sources.** Every market claim, best practice, statistic, or "industry uses X" assertion must link to the URL it came from. Unsourced claims are not allowed.
|
|
24
|
+
4. **Multiple options.** Always present at least two alternatives with explicit pros/cons. Never single-answer. The user is brainstorming, not asking for a verdict.
|
|
25
|
+
5. **Honest gaps.** When research is incomplete or a decision needs more input, surface it explicitly under "Open questions" — do not paper over.
|
|
26
|
+
6. **No AI attribution in any artifact produced.** Consistent with the global commit-authorship rule: if the brainstorm output ever gets pasted into a commit, doc, or message, it must not carry `Co-Authored-By: Claude / Anthropic / AI / Generated with [...]` lines.
|
|
27
|
+
|
|
28
|
+
## Inputs
|
|
29
|
+
|
|
30
|
+
The skill takes one required argument (the topic) and optional flags:
|
|
31
|
+
|
|
32
|
+
| Param | Default | Description |
|
|
33
|
+
|-------|---------|-------------|
|
|
34
|
+
| `<topic>` | required | Free-form text describing the problem, decision, or idea to brainstorm |
|
|
35
|
+
| `--depth <level>` | `medium` | `quick` (3 web queries, 1 agent), `medium` (6 queries, 2-3 agents), `deep` (10+ queries, 4 agents + tech-lead) |
|
|
36
|
+
| `--no-web` | off | Skip web research entirely. Agents-only mode. Use when offline or when the topic is purely internal-codebase. |
|
|
37
|
+
| `--focus <domain>` | auto | Force a domain bias: `frontend`, `backend`, `infra`, `data`, `security`, `business`, `mobile`. Auto-detection scans the topic text for keywords. |
|
|
38
|
+
| `--sources <N>` | 5 | Cap on web sources cited per section. Avoids dump of every result. |
|
|
39
|
+
|
|
40
|
+
## Step 1: Topic Understanding
|
|
41
|
+
|
|
42
|
+
Read the user's prompt and extract:
|
|
43
|
+
- **Problem/decision**: what is being decided? Phrase it as a question.
|
|
44
|
+
- **Constraints**: tech stack, team size, scale, budget, timeline (if mentioned or inferable from `git log` / `package.json` / `README`).
|
|
45
|
+
- **Existing context**: scan the current repo for related code, prior decisions in `CHANGELOG.md` or ADRs (`docs/adr/`, `architecture/`).
|
|
46
|
+
- **Domain(s)**: classify into one or more of `frontend / backend / infra / data / security / business / mobile`.
|
|
47
|
+
- **What "done" looks like**: what would satisfy the user — a single recommendation, multiple paths to consider, a comparison table, a risk inventory?
|
|
48
|
+
|
|
49
|
+
If the topic is ambiguous, ask **one** clarifying question before proceeding. Do not ask a list of questions; pick the most load-bearing one.
|
|
50
|
+
|
|
51
|
+
## Step 2: Research Plan
|
|
52
|
+
|
|
53
|
+
Build a research plan with:
|
|
54
|
+
|
|
55
|
+
### Web queries (skip if `--no-web`)
|
|
56
|
+
|
|
57
|
+
Construct 3-10 targeted queries (count from `--depth`). Use the **current year** in queries that benefit from recency:
|
|
58
|
+
|
|
59
|
+
- `{topic} best practices {year}`
|
|
60
|
+
- `{topic} {dominant_stack} examples`
|
|
61
|
+
- `{topic} alternatives comparison`
|
|
62
|
+
- `{topic} common pitfalls`
|
|
63
|
+
- `{topic} performance` / `security` / `scalability` / `cost`
|
|
64
|
+
- `{topic} case study {year}` (for industry examples)
|
|
65
|
+
- `{topic} open source` (if implementation references would help)
|
|
66
|
+
- `{topic} vs {known_alternative}` (if a comparison is implicit)
|
|
67
|
+
|
|
68
|
+
Avoid:
|
|
69
|
+
- Generic queries like "{topic}" alone (returns marketing pages).
|
|
70
|
+
- Queries that the user can find better via their internal docs (e.g., proprietary product internals).
|
|
71
|
+
|
|
72
|
+
### Agents
|
|
73
|
+
|
|
74
|
+
Pick agents based on detected domains. For `--depth quick`: pick the single most relevant. For `medium`: 2-3. For `deep`: 4 + tech-lead. Mapping:
|
|
75
|
+
|
|
76
|
+
| Domain | Primary agent |
|
|
77
|
+
|--------|---------------|
|
|
78
|
+
| frontend | senior-developer (UX/perf perspective) |
|
|
79
|
+
| backend | senior-developer + senior-architect |
|
|
80
|
+
| infra | senior-architect + senior-dev-security |
|
|
81
|
+
| data | senior-dba + senior-architect |
|
|
82
|
+
| security | senior-dev-security + senior-architect |
|
|
83
|
+
| business | product-owner |
|
|
84
|
+
| testing | senior-qa |
|
|
85
|
+
| code quality | senior-dev-reviewer |
|
|
86
|
+
|
|
87
|
+
`tech-lead` is included only at `--depth deep` (or whenever 3+ agents participate, to consolidate).
|
|
88
|
+
|
|
89
|
+
## Step 3: Parallel Research and Agent Spawn
|
|
90
|
+
|
|
91
|
+
Run web queries and agent invocations **in parallel** in a single message:
|
|
92
|
+
- One `WebSearch` tool call per query.
|
|
93
|
+
- One `Agent` tool call per specialist.
|
|
94
|
+
|
|
95
|
+
Per-agent prompt template:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
You are participating in a brainstorm — pre-implementation thinking.
|
|
99
|
+
|
|
100
|
+
## Topic
|
|
101
|
+
{topic restated}
|
|
102
|
+
|
|
103
|
+
## What we know so far
|
|
104
|
+
{problem framing, constraints, existing context}
|
|
105
|
+
|
|
106
|
+
## Your perspective
|
|
107
|
+
As {agent role}, contribute:
|
|
108
|
+
1. The 1-3 approaches you would consider, with one-line pros/cons each.
|
|
109
|
+
2. Domain-specific risks the user should weigh.
|
|
110
|
+
3. Open questions that need answers before deciding.
|
|
111
|
+
4. (Optional) One concrete example from your experience or prior projects.
|
|
112
|
+
|
|
113
|
+
Format: at most 400 words. Bullet points fine. Do NOT produce a full review template.
|
|
114
|
+
Do NOT recommend code changes — this is exploration, not implementation.
|
|
115
|
+
If you do not have enough context to contribute meaningfully, say so explicitly.
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Step 4: Findings Synthesis
|
|
119
|
+
|
|
120
|
+
Aggregate web findings and agent perspectives into:
|
|
121
|
+
|
|
122
|
+
### Market research section
|
|
123
|
+
Group findings by category. **Cite every claim.** Example:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
### What the industry does
|
|
127
|
+
- Stripe and Block use a "saga" pattern for cross-service refund flows — [Stripe Engineering blog](url), [Square's saga implementation](url).
|
|
128
|
+
- 7 of the top 10 fintech APIs (per State of API 2026) implement idempotency keys via request headers — [State of API 2026](url).
|
|
129
|
+
|
|
130
|
+
### Best practices
|
|
131
|
+
- Always include a `request_id` in idempotency keys to disambiguate retries — [GitHub's idempotency guide](url).
|
|
132
|
+
|
|
133
|
+
### Pitfalls / anti-patterns
|
|
134
|
+
- Don't use the database PK as an idempotency key — collisions across retries break replays — [Postgres weekly issue 543](url).
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Options matrix
|
|
138
|
+
|
|
139
|
+
Build a table of **3-5 alternatives**. Columns:
|
|
140
|
+
|
|
141
|
+
| # | Approach | How it works | Pros | Cons | Risk | Best when |
|
|
142
|
+
|---|----------|--------------|------|------|------|-----------|
|
|
143
|
+
|
|
144
|
+
Each row is one viable path. "Approach" is short (3-6 words). "How it works" is one sentence. Pros/cons are bullet-style condensed.
|
|
145
|
+
|
|
146
|
+
### Agent perspectives
|
|
147
|
+
|
|
148
|
+
One collapsible section per agent that participated:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
<details>
|
|
152
|
+
<summary>senior-architect</summary>
|
|
153
|
+
{their perspective bullet-pointed}
|
|
154
|
+
</details>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Step 5: Tech-Lead Recommendation
|
|
158
|
+
|
|
159
|
+
If `--depth deep` (or 3+ agents participated), spawn the `tech-lead` agent with:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
You are consolidating a brainstorm. Pick one option and justify.
|
|
163
|
+
|
|
164
|
+
## Topic
|
|
165
|
+
{topic}
|
|
166
|
+
|
|
167
|
+
## Options matrix
|
|
168
|
+
{the matrix from step 4}
|
|
169
|
+
|
|
170
|
+
## Web findings summary
|
|
171
|
+
{condensed market research, with sources}
|
|
172
|
+
|
|
173
|
+
## Specialist perspectives
|
|
174
|
+
{condensed bullets from each agent}
|
|
175
|
+
|
|
176
|
+
## Your task
|
|
177
|
+
1. Pick ONE option from the matrix as the recommendation.
|
|
178
|
+
2. Explain in 3-5 sentences why this option, with the trade-offs you accepted.
|
|
179
|
+
3. List the top 2-3 open questions that must be answered before implementation begins.
|
|
180
|
+
4. Suggest the immediate next step (e.g., spike, prototype, more research, /squad implement).
|
|
181
|
+
|
|
182
|
+
Format: at most 400 words. No long template. No scorecard.
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
For `quick` and `medium` depth, the synthesizing skill itself produces the recommendation directly (no separate tech-lead spawn).
|
|
186
|
+
|
|
187
|
+
## Step 6: Delivery
|
|
188
|
+
|
|
189
|
+
Output in this format:
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
# Brainstorm: {short topic}
|
|
193
|
+
|
|
194
|
+
## Topic
|
|
195
|
+
{problem framing in 1-2 sentences}
|
|
196
|
+
|
|
197
|
+
## Context I gathered
|
|
198
|
+
- {key fact 1 from repo / git / user prompt}
|
|
199
|
+
- {key fact 2}
|
|
200
|
+
|
|
201
|
+
## Market research
|
|
202
|
+
|
|
203
|
+
### What the industry does
|
|
204
|
+
- {finding} — [source title](url)
|
|
205
|
+
- {finding} — [source title](url)
|
|
206
|
+
|
|
207
|
+
### Best practices
|
|
208
|
+
- {practice} — [source](url)
|
|
209
|
+
|
|
210
|
+
### Pitfalls / anti-patterns
|
|
211
|
+
- {pitfall} — [source](url)
|
|
212
|
+
|
|
213
|
+
## Options matrix
|
|
214
|
+
|
|
215
|
+
| # | Approach | How it works | Pros | Cons | Risk | Best when |
|
|
216
|
+
|---|----------|--------------|------|------|------|-----------|
|
|
217
|
+
| A | ... | ... | ... | ... | Low | small scale, low traffic |
|
|
218
|
+
| B | ... | ... | ... | ... | Med | growth phase |
|
|
219
|
+
| C | ... | ... | ... | ... | High | enterprise / regulated |
|
|
220
|
+
|
|
221
|
+
## Agent perspectives
|
|
222
|
+
|
|
223
|
+
<details><summary>senior-architect</summary>{view}</details>
|
|
224
|
+
<details><summary>senior-developer</summary>{view}</details>
|
|
225
|
+
|
|
226
|
+
## Recommendation
|
|
227
|
+
**Option {letter}** — {one-paragraph justification including the trade-offs accepted}.
|
|
228
|
+
|
|
229
|
+
## Open questions
|
|
230
|
+
- {gap 1 — needs decision or more research}
|
|
231
|
+
- {gap 2}
|
|
232
|
+
- {gap 3}
|
|
233
|
+
|
|
234
|
+
## Next steps
|
|
235
|
+
- `/squad implement {selected option}` to execute
|
|
236
|
+
- `/brainstorm --focus {domain} {sub-topic}` to deep-dive on a specific concern
|
|
237
|
+
- Spike / prototype: {1-2 line description if appropriate}
|
|
238
|
+
- Continue research on: {gap}
|
|
239
|
+
|
|
240
|
+
Sources used:
|
|
241
|
+
- [Title 1](url)
|
|
242
|
+
- [Title 2](url)
|
|
243
|
+
- ...
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
If `--no-web` was passed, omit "Market research" section and replace with a one-line note: `Web research disabled — agents-only brainstorm.`
|
|
247
|
+
|
|
248
|
+
If the user passed `--depth quick`, output is condensed: skip "Agent perspectives" details, drop the matrix to 2-3 options, and replace the recommendation paragraph with one sentence.
|
|
249
|
+
|
|
250
|
+
## Edge Cases
|
|
251
|
+
|
|
252
|
+
- **Topic is too vague** ("help me think about scaling") → ask one clarifying question first; do not run research blindly.
|
|
253
|
+
- **Topic is purely internal** (only repo-specific, no public reference) → suggest `--no-web` and note that web research is unlikely to add value.
|
|
254
|
+
- **Topic touches a regulated domain** (PCI, HIPAA, GDPR, SOX) → flag the regulatory angle in the Open questions section even if the user did not mention it. Do not produce legal/compliance advice — point at the right specialists/docs.
|
|
255
|
+
- **Web search returns thin results** → state honestly: "Web research surfaced limited material; the recommendation leans on agent perspectives and codebase context." Do not invent citations.
|
|
256
|
+
- **Agent reports "not enough context"** → record it and proceed; do not retry with more context just to force an opinion.
|
|
257
|
+
- **The user wants implementation, not brainstorm** → redirect: "This sounds like a `/squad` task. `/brainstorm` is for pre-implementation exploration."
|
|
258
|
+
|
|
259
|
+
## Boundaries
|
|
260
|
+
|
|
261
|
+
- This skill never edits files.
|
|
262
|
+
- This skill never runs state-mutating git commands.
|
|
263
|
+
- This skill never claims authority for legal/regulatory/compliance verdicts — it points at sources and specialists.
|
|
264
|
+
- This skill never invents URLs or sources. If unsure, omit the citation and note the gap.
|
|
265
|
+
- This skill produces text only.
|
|
266
|
+
|
|
267
|
+
## Considerations
|
|
268
|
+
|
|
269
|
+
### Cost vs depth
|
|
270
|
+
- `quick`: ~3 web queries + 1 agent. Roughly 5-10K tokens. Useful for quick reality-checks.
|
|
271
|
+
- `medium` (default): ~6 queries + 2-3 agents. ~20-40K tokens. Useful for genuine option exploration.
|
|
272
|
+
- `deep`: ~10+ queries + 4 agents + tech-lead. ~60-100K tokens. Useful for high-stakes decisions where multiple stakeholders need to align.
|
|
273
|
+
|
|
274
|
+
### When to use vs alternatives
|
|
275
|
+
- Use `/brainstorm` when: deciding *what* to build, comparing approaches, scanning industry, exploring a problem space.
|
|
276
|
+
- Use `/squad` when: you've decided and want to implement.
|
|
277
|
+
- Use `/squad-review` when: implementation is done and you want a multi-perspective review.
|
|
278
|
+
- Use `WebSearch` directly when: you need one specific answer, not a brainstorm framing.
|
|
279
|
+
|
|
280
|
+
### Sources reliability
|
|
281
|
+
Prefer (in this order): official docs, recognized engineering blogs (e.g., Stripe, AWS, Cloudflare, Google Cloud, Microsoft, Netflix Tech Blog), academic / standards bodies, recognized newsletters (Pragmatic Engineer, Increment), GitHub READMEs of widely-adopted libraries, conference talks. Avoid: SEO listicles, vendor-marketing pieces masquerading as articles, AI-generated content farms.
|
|
282
|
+
|
|
283
|
+
### Output format consistency
|
|
284
|
+
Always close with a "Next steps" block and a flat list of all sources used. The Next steps block is the bridge from brainstorm to action — never omit it.
|