@slamb2k/mad-skills 2.0.51 → 2.0.55

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mad-skills",
3
3
  "description": "AI-assisted planning, development and governance tools",
4
- "version": "2.0.51",
4
+ "version": "2.0.55",
5
5
  "author": {
6
6
  "name": "slamb2k",
7
7
  "url": "https://github.com/slamb2k"
@@ -2,28 +2,61 @@
2
2
 
3
3
  const config = require('./config.cjs');
4
4
 
5
+ // Unicode banner (Delta Corps Priest 1) — used when the terminal supports UTF-8.
5
6
  // prettier-ignore
6
- const BANNER_LINES = [
7
- '::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::',
8
- ":::::'##::::'##::::'###::::'########::::::'######::'##:::'##:'####:'##:::::::'##::::::::'######::::::::",
9
- "::::: ###::'###:::'## ##::: ##.... ##::::'##... ##: ##::'##::. ##:: ##::::::: ##:::::::'##... ##:::::::",
10
- "::::: ####'####::'##:. ##:: ##:::: ##:::: ##:::..:: ##:'##:::: ##:: ##::::::: ##::::::: ##:::..::::::::",
11
- "::::: ## ### ##:'##:::. ##: ##:::: ##::::. ######:: #####::::: ##:: ##::::::: ##:::::::. ######::::::::",
12
- "::::: ##. #: ##: #########: ##:::: ##:::::..... ##: ##. ##:::: ##:: ##::::::: ##::::::::..... ##:::::::",
13
- "::::: ##:.:: ##: ##.... ##: ##:::: ##::::'##::: ##: ##:. ##::: ##:: ##::::::: ##:::::::'##::: ##:::::::",
14
- "::::: ##:::: ##: ##:::: ##: ########:::::. ######:: ##::. ##:'####: ########: ########:. ######::::::::",
15
- "::::::..:::::..::..:::::..::........:::::::......:::..::::..::....::........::........:::......:::::::::",
7
+ const BANNER_UNICODE = [
8
+ " ▄▄▄▄███▄▄▄▄ ▄████████ ████████▄",
9
+ "▄██▀▀▀███▀▀▀██▄ ███ ███ ███ ▀███",
10
+ "███ ███ ███ ███ ███ ███ ███",
11
+ "███ ███ ███ ███ ███ ███ ███",
12
+ "███ ███ ███ ▀███████████ ███ ███",
13
+ "███ ███ ███ ███ ███ ███ ███",
14
+ "███ ███ ███ ███ ███ ███ ▄███",
15
+ " ▀█ ███ █▀ ███ █▀ ████████▀",
16
+ "",
17
+ " ▄████████ ▄█ ▄█▄ ▄█ ▄█ ▄█ ▄████████",
18
+ " ███ ███ ███ ▄███▀ ███ ███ ███ ███ ███",
19
+ " ███ █▀ ███▐██▀ ███▌ ███ ███ ███ █▀",
20
+ " ███ ▄█████▀ ███▌ ███ ███ ███",
21
+ "▀███████████ ▀▀█████▄ ███▌ ███ ███ ▀███████████",
22
+ " ███ ███▐██▄ ███ ███ ███ ███",
23
+ " ▄█ ███ ███ ▀███▄ ███ ███▌ ▄ ███▌ ▄ ▄█ ███",
24
+ " ▄████████▀ ███ ▀█▀ █▀ █████▄▄██ █████▄▄██ ▄████████▀",
25
+ " ▀ ▀ ▀",
16
26
  ];
17
27
 
18
- const SEPARATOR = '\u2500'.repeat(70);
28
+ // ASCII fallback (Rowan Cap) — used when the terminal locale is not UTF-8.
29
+ // prettier-ignore
30
+ const BANNER_ASCII = [
31
+ " dMMMMMMMMb .aMMMb dMMMMb",
32
+ " dMP\"dMP\"dMP dMP\"dMP dMP VMP",
33
+ " dMP dMP dMP dMMMMMP dMP dMP",
34
+ " dMP dMP dMP dMP dMP dMP.aMP",
35
+ "dMP dMP dMP dMP dMP dMMMMP\"",
36
+ "",
37
+ " .dMMMb dMP dMP dMP dMP dMP .dMMMb",
38
+ " dMP\" VP dMP.dMP amr dMP dMP dMP\" VP",
39
+ " VMMMb dMMMMK\" dMP dMP dMP VMMMb",
40
+ "dP .dMP dMP\"AMF dMP dMP dMP dP .dMP",
41
+ "VMMMP\" dMP dMP dMP dMMMMMP dMMMMMP VMMMP\"",
42
+ ];
43
+
44
+ // True when the terminal locale advertises UTF-8, so box-drawing glyphs render.
45
+ function supportsUnicode() {
46
+ const locale = process.env.LC_ALL || process.env.LC_CTYPE || process.env.LANG || '';
47
+ return /utf-?8/i.test(locale);
48
+ }
19
49
 
20
50
  function getBanner() {
51
+ const unicode = supportsUnicode();
52
+ const lines = unicode ? BANNER_UNICODE : BANNER_ASCII;
53
+ const separator = (unicode ? '─' : '-').repeat(70);
21
54
  return [
22
- ...BANNER_LINES,
23
- SEPARATOR,
55
+ ...lines,
56
+ separator,
24
57
  ` Session Guard v${config.version}`,
25
- SEPARATOR,
58
+ separator,
26
59
  ].join('\n');
27
60
  }
28
61
 
29
- module.exports = { getBanner, BANNER_MARKER: '::::::::::::::::::::' };
62
+ module.exports = { getBanner, supportsUnicode, BANNER_MARKER: 'Session Guard' };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slamb2k/mad-skills",
3
- "version": "2.0.51",
3
+ "version": "2.0.55",
4
4
  "description": "Claude Code skills collection — full lifecycle development tools",
5
5
  "type": "module",
6
6
  "repository": {
@@ -11,6 +11,8 @@
11
11
  "skills/",
12
12
  "agents/",
13
13
  "hooks/",
14
+ "scripts/lib/",
15
+ "references/",
14
16
  ".claude-plugin/"
15
17
  ],
16
18
  "scripts": {
@@ -22,7 +24,8 @@
22
24
  "build:skills": "node scripts/package-skills.js",
23
25
  "build": "npm run build:manifests && npm run build:skills",
24
26
  "prepublishOnly": "npm run validate && npm run build:manifests",
25
- "test": "npm run validate && npm run lint && npm run eval"
27
+ "test:unit": "node --test scripts/lib/superpowers.test.js",
28
+ "test": "npm run validate && npm run lint && npm run test:unit && npm run eval"
26
29
  },
27
30
  "keywords": [
28
31
  "claude",
@@ -0,0 +1,342 @@
1
+ # Azure DevOps CLI Reference for Claude Code
2
+
3
+ This document provides guidance for LLM agents constructing Azure DevOps CLI
4
+ commands. It addresses common pitfalls, inconsistent flag support across
5
+ subcommands, and REST API authentication patterns.
6
+
7
+ ## Critical: `--project` Flag Is NOT Universal
8
+
9
+ The `--project` flag is **only supported by some `az devops` subcommands**.
10
+ Using it where it is not supported produces `ERROR: unrecognized arguments`.
11
+
12
+ ### Commands that accept `--project`
13
+
14
+ | Command | `--project` | Notes |
15
+ |---------|------------|-------|
16
+ | `az repos pr create` | YES | Required if not configured via defaults |
17
+ | `az repos pr list` | YES | Filters by project |
18
+ | `az pipelines list` | YES | |
19
+ | `az pipelines runs list` | YES | |
20
+ | `az pipelines run` | YES | Queue a new run |
21
+ | `az repos policy list` | YES | |
22
+
23
+ ### Commands that DO NOT accept `--project`
24
+
25
+ | Command | `--project` | Use instead |
26
+ |---------|------------|------------|
27
+ | `az repos pr update` | NO | `--org` only, or configure defaults |
28
+ | `az repos pr show` | NO | `--org` only, or configure defaults |
29
+ | `az devops invoke` | NO | Pass project in `--route-parameters` |
30
+
31
+ ### Safe pattern
32
+
33
+ Always configure defaults at the start of a session, then omit `--project`
34
+ from commands that don't support it:
35
+
36
+ ```bash
37
+ az devops configure --defaults \
38
+ organization="$AZDO_ORG_URL" \
39
+ project="$AZDO_PROJECT"
40
+ ```
41
+
42
+ After this, commands that support `--project` will use the default, and
43
+ commands that don't (like `pr update` and `pr show`) will detect the project
44
+ from the `--org` URL or the PR ID.
45
+
46
+ For `az devops invoke`, pass the project via route parameters:
47
+
48
+ ```bash
49
+ az devops invoke \
50
+ --area build --resource timeline \
51
+ --route-parameters buildId=12345 project="$AZDO_PROJECT" \
52
+ --org "$AZDO_ORG_URL" -o json
53
+ ```
54
+
55
+ ---
56
+
57
+ ## PR Merge Pattern
58
+
59
+ The correct command to squash-merge a PR:
60
+
61
+ ```bash
62
+ az repos pr update \
63
+ --id "$PR_NUMBER" \
64
+ --status completed \
65
+ --squash true \
66
+ --delete-source-branch true \
67
+ --merge-commit-message "commit message here" \
68
+ --org "$AZDO_ORG_URL"
69
+ ```
70
+
71
+ If the PR has branch policies that haven't been satisfied (e.g., no CI checks
72
+ registered, no required reviewers), add:
73
+
74
+ ```bash
75
+ --bypass-policy true \
76
+ --bypass-policy-reason "Reason for bypass"
77
+ ```
78
+
79
+ **Important:** After calling `pr update --status completed`, the merge may be
80
+ asynchronous. Poll with:
81
+
82
+ ```bash
83
+ az repos pr show --id "$PR_NUMBER" --query status -o tsv --org "$AZDO_ORG_URL"
84
+ ```
85
+
86
+ Expected result: `completed`. If still `active`, wait 5-10 seconds and retry.
87
+
88
+ ---
89
+
90
+ ## CI Pipeline Monitoring
91
+
92
+ ### Branch name mismatch
93
+
94
+ Azure DevOps PR builds have `sourceBranch` set to `refs/pull/<N>/merge`, NOT
95
+ the feature branch name. When listing runs for a PR:
96
+
97
+ ```bash
98
+ # WRONG — will return no results
99
+ az pipelines runs list --branch "feat/my-feature" ...
100
+
101
+ # CORRECT — match the PR merge ref
102
+ az pipelines runs list --branch "refs/pull/$PR_NUMBER/merge" \
103
+ --org "$AZDO_ORG_URL" --project "$AZDO_PROJECT" \
104
+ --top 1 -o json
105
+ ```
106
+
107
+ Alternatively, list without branch filter and filter in `jq`:
108
+
109
+ ```bash
110
+ az pipelines runs list --top 10 \
111
+ --org "$AZDO_ORG_URL" --project "$AZDO_PROJECT" -o json \
112
+ | jq "[.[] | select(.sourceBranch == \"refs/pull/$PR_NUMBER/merge\")]"
113
+ ```
114
+
115
+ ### Polling for completion
116
+
117
+ ```bash
118
+ RESULT=$(az pipelines runs show --id "$RUN_ID" \
119
+ --org "$AZDO_ORG_URL" --project "$AZDO_PROJECT" \
120
+ --query result -o tsv)
121
+
122
+ # RESULT is one of: succeeded, failed, canceled, (empty if still running)
123
+ ```
124
+
125
+ ### Getting failed job details
126
+
127
+ Use the timeline API to find which jobs/steps failed:
128
+
129
+ ```bash
130
+ az devops invoke \
131
+ --area build --resource timeline \
132
+ --route-parameters buildId="$RUN_ID" project="$AZDO_PROJECT" \
133
+ --org "$AZDO_ORG_URL" -o json \
134
+ | jq '[.records[] | select(.result=="failed") | {name, type}]'
135
+ ```
136
+
137
+ To get log output from a failed step, extract the log URL from the timeline
138
+ record and fetch it with `curl` using PAT auth (see REST API section below).
139
+
140
+ ---
141
+
142
+ ## URL Formats and Org Detection
143
+
144
+ Azure DevOps has two URL formats. Both are valid, but REST API calls via
145
+ `curl` may only work with one depending on org configuration.
146
+
147
+ | Format | Example |
148
+ |--------|---------|
149
+ | Modern | `https://dev.azure.com/{ORG}/{PROJECT}/_git/{REPO}` |
150
+ | Legacy | `https://{ORG}.visualstudio.com/{PROJECT}/_git/{REPO}` |
151
+ | SSH | `{ORG}@vs-ssh.visualstudio.com:v3/{ORG}/{PROJECT}/{REPO}` |
152
+
153
+ ### Preserve the original URL format
154
+
155
+ When the remote uses `visualstudio.com`, keep that format for REST API calls.
156
+ Do NOT normalize to `dev.azure.com` — some legacy organizations only respond
157
+ to the original domain.
158
+
159
+ ```bash
160
+ REMOTE_URL=$(git remote get-url origin 2>/dev/null)
161
+
162
+ if echo "$REMOTE_URL" | grep -q 'dev\.azure\.com'; then
163
+ AZDO_ORG=$(echo "$REMOTE_URL" | sed -n 's|.*dev\.azure\.com/\([^/]*\)/.*|\1|p')
164
+ AZDO_ORG_URL="https://dev.azure.com/$AZDO_ORG"
165
+ elif echo "$REMOTE_URL" | grep -q 'visualstudio\.com'; then
166
+ AZDO_ORG=$(echo "$REMOTE_URL" | sed -n 's|.*//\([^.]*\)\.visualstudio\.com.*|\1|p')
167
+ # Keep the original domain for REST API compatibility
168
+ AZDO_ORG_URL="https://${AZDO_ORG}.visualstudio.com"
169
+ fi
170
+ ```
171
+
172
+ ### URL-decoding project names
173
+
174
+ Project names with spaces are URL-encoded in remote URLs (e.g.,
175
+ `Velrada%20AI%20Agents`). The common `printf '%b'` approach fails when
176
+ `%20` is followed by hex characters (A-F, 0-9):
177
+
178
+ ```bash
179
+ # BROKEN — fails on "Velrada%20AI%20Agents" (interprets %20A as \x20A)
180
+ AZDO_PROJECT=$(printf '%b' "${AZDO_PROJECT//%/\\x}")
181
+
182
+ # CORRECT — use Python for reliable URL decoding
183
+ AZDO_PROJECT=$(python3 -c "import urllib.parse; print(urllib.parse.unquote('$AZDO_PROJECT_URL_SAFE'))")
184
+ ```
185
+
186
+ Keep both the URL-safe and decoded versions:
187
+
188
+ ```bash
189
+ AZDO_PROJECT_URL_SAFE="Velrada%20AI%20Agents" # for REST API URL paths
190
+ AZDO_PROJECT="Velrada AI Agents" # for CLI --project flags
191
+ ```
192
+
193
+ ---
194
+
195
+ ## REST API via `curl`
196
+
197
+ ### Authentication
198
+
199
+ Use the `AZURE_DEVOPS_EXT_PAT` environment variable (this is the standard env
200
+ var that `az devops login` also reads):
201
+
202
+ ```bash
203
+ TOKEN=$(printf ":%s" "$AZURE_DEVOPS_EXT_PAT" | base64 -w0)
204
+ AUTH="Authorization: Basic $TOKEN"
205
+ ```
206
+
207
+ ### DO NOT use `az rest` for Azure DevOps
208
+
209
+ `az rest` is designed for Azure Resource Manager (ARM) APIs. It cannot
210
+ automatically derive the correct Azure AD resource for Azure DevOps endpoints.
211
+ Even with `--resource "499b84ac-1321-427f-aa17-267ca6975798"` (the Azure DevOps
212
+ resource ID), it often fails for legacy organizations.
213
+
214
+ **Always use `curl` with PAT-based Basic auth for Azure DevOps REST APIs.**
215
+
216
+ ### Common REST API patterns
217
+
218
+ ```bash
219
+ # Build timeline (get failed steps)
220
+ curl -s -H "$AUTH" \
221
+ "${AZDO_ORG_URL}/${AZDO_PROJECT_URL_SAFE}/_apis/build/builds/${BUILD_ID}/timeline?api-version=7.1"
222
+
223
+ # Build logs (get log content for a specific log ID)
224
+ curl -s -H "$AUTH" \
225
+ "${AZDO_ORG_URL}/${AZDO_PROJECT_URL_SAFE}/_apis/build/builds/${BUILD_ID}/logs/${LOG_ID}?api-version=7.1"
226
+
227
+ # PR details
228
+ curl -s -H "$AUTH" \
229
+ "${AZDO_ORG_URL}/${AZDO_PROJECT_URL_SAFE}/_apis/git/repositories/${REPO_NAME}/pullRequests/${PR_NUMBER}?api-version=7.1"
230
+
231
+ # Complete a PR (REST fallback)
232
+ curl -s -X PATCH -H "$AUTH" -H "Content-Type: application/json" \
233
+ "${AZDO_ORG_URL}/${AZDO_PROJECT_URL_SAFE}/_apis/git/repositories/${REPO_NAME}/pullRequests/${PR_NUMBER}?api-version=7.1" \
234
+ -d '{
235
+ "status": "completed",
236
+ "completionOptions": {
237
+ "squashMerge": true,
238
+ "deleteSourceBranch": true,
239
+ "mergeCommitMessage": "commit message"
240
+ }
241
+ }'
242
+ ```
243
+
244
+ ---
245
+
246
+ ## JSON Safety: Validate Before Piping to `jq`
247
+
248
+ Azure CLI commands can output warnings, error messages, or HTML instead of
249
+ JSON. Always validate before piping:
250
+
251
+ ```bash
252
+ # Pattern 1: Capture output, validate, then parse
253
+ OUTPUT=$(az pipelines runs show --id "$RUN_ID" --org "$AZDO_ORG_URL" -o json 2>&1)
254
+ if echo "$OUTPUT" | jq empty 2>/dev/null; then
255
+ echo "$OUTPUT" | jq '.result'
256
+ else
257
+ echo "ERROR: Non-JSON response: $OUTPUT" >&2
258
+ fi
259
+
260
+ # Pattern 2: Use --output json and redirect stderr
261
+ RESULT=$(az repos pr show --id "$PR_NUMBER" --query status -o tsv 2>/dev/null)
262
+
263
+ # Pattern 3: For curl, check HTTP status
264
+ HTTP_CODE=$(curl -s -o /tmp/response.json -w "%{http_code}" -H "$AUTH" "$URL")
265
+ if [ "$HTTP_CODE" = "200" ]; then
266
+ jq '.' /tmp/response.json
267
+ else
268
+ echo "ERROR: HTTP $HTTP_CODE" >&2
269
+ fi
270
+ ```
271
+
272
+ **Never swallow stderr with `2>/dev/null` on commands that might fail.**
273
+ Capture stderr to a variable instead:
274
+
275
+ ```bash
276
+ OUTPUT=$(az repos pr update --id "$PR_NUMBER" --status completed 2>&1)
277
+ EXIT_CODE=$?
278
+ if [ $EXIT_CODE -ne 0 ]; then
279
+ echo "MERGE FAILED: $OUTPUT" >&2
280
+ fi
281
+ ```
282
+
283
+ ---
284
+
285
+ ## Quick Reference: Common Operations
286
+
287
+ ### Create PR
288
+
289
+ ```bash
290
+ az repos pr create \
291
+ --title "feat: description" \
292
+ --description "## Summary ..." \
293
+ --source-branch "$BRANCH" \
294
+ --target-branch main \
295
+ --org "$AZDO_ORG_URL" \
296
+ --project "$AZDO_PROJECT" \
297
+ --output json
298
+ ```
299
+
300
+ ### List runs for a PR
301
+
302
+ ```bash
303
+ az pipelines runs list \
304
+ --branch "refs/pull/$PR_NUMBER/merge" \
305
+ --top 1 \
306
+ --org "$AZDO_ORG_URL" \
307
+ --project "$AZDO_PROJECT" \
308
+ -o json
309
+ ```
310
+
311
+ ### Queue a pipeline run
312
+
313
+ ```bash
314
+ az pipelines run \
315
+ --id "$PIPELINE_ID" \
316
+ --branch "$BRANCH" \
317
+ --org "$AZDO_ORG_URL" \
318
+ --project "$AZDO_PROJECT" \
319
+ -o json
320
+ ```
321
+
322
+ ### Complete (merge) a PR
323
+
324
+ ```bash
325
+ az repos pr update \
326
+ --id "$PR_NUMBER" \
327
+ --status completed \
328
+ --squash true \
329
+ --delete-source-branch true \
330
+ --merge-commit-message "message" \
331
+ --org "$AZDO_ORG_URL"
332
+ ```
333
+
334
+ ### Check PR status
335
+
336
+ ```bash
337
+ az repos pr show \
338
+ --id "$PR_NUMBER" \
339
+ --query status \
340
+ -o tsv \
341
+ --org "$AZDO_ORG_URL"
342
+ ```
@@ -0,0 +1,88 @@
1
+ # Azure DevOps Platform Support
2
+
3
+ Shared procedures for AzDO tooling detection and configuration validation.
4
+ Referenced by SKILL.md during pre-flight when `PLATFORM == azdo`.
5
+
6
+ ## AzDO Tooling Detection
7
+
8
+ When `PLATFORM == azdo`, determine which tooling is available. Set `AZDO_MODE`
9
+ for use in all subsequent phases:
10
+
11
+ ```bash
12
+ if az devops -h &>/dev/null; then
13
+ AZDO_MODE="cli"
14
+ else
15
+ AZDO_MODE="rest"
16
+ fi
17
+ ```
18
+
19
+ - **`cli`**: Use `az repos` / `az pipelines` commands (preferred)
20
+ - **`rest`**: Use Azure DevOps REST API via `curl`. Requires a PAT (personal
21
+ access token) in `AZURE_DEVOPS_EXT_PAT` or `AZDO_PAT` env var. If no PAT
22
+ is found, prompt the user to either install the CLI or set the env var.
23
+
24
+ Report in pre-flight:
25
+ - ✅ `az devops cli` — version found
26
+ - ⚠️ `az devops cli` — not found → using REST API fallback
27
+ - ❌ `az devops cli` — not found, no PAT configured → halt with setup instructions
28
+
29
+ ## AzDO Configuration Validation
30
+
31
+ When `PLATFORM == azdo`, extract organization and project from the remote URL
32
+ and validate they are usable. These values are needed by every `az repos` /
33
+ `az pipelines` command and every REST API call.
34
+
35
+ ```bash
36
+ # Extract org and project from remote URL patterns:
37
+ # https://dev.azure.com/{ORG}/{PROJECT}/_git/{REPO}
38
+ # https://{ORG}@dev.azure.com/{ORG}/{PROJECT}/_git/{REPO}
39
+ # {ORG}@vs-ssh.visualstudio.com:v3/{ORG}/{PROJECT}/{REPO}
40
+
41
+ REMOTE_URL=$(git remote get-url origin 2>/dev/null)
42
+
43
+ if echo "$REMOTE_URL" | grep -q 'dev\.azure\.com'; then
44
+ AZDO_ORG=$(echo "$REMOTE_URL" | sed -n 's|.*dev\.azure\.com/\([^/]*\)/.*|\1|p')
45
+ AZDO_PROJECT=$(echo "$REMOTE_URL" | sed -n 's|.*dev\.azure\.com/[^/]*/\([^/]*\)/.*|\1|p')
46
+ AZDO_ORG_URL="https://dev.azure.com/$AZDO_ORG"
47
+ elif echo "$REMOTE_URL" | grep -q 'vs-ssh\.visualstudio\.com'; then
48
+ AZDO_ORG=$(echo "$REMOTE_URL" | sed -n 's|.*vs-ssh\.visualstudio\.com:v3/\([^/]*\)/.*|\1|p')
49
+ AZDO_PROJECT=$(echo "$REMOTE_URL" | sed -n 's|.*vs-ssh\.visualstudio\.com:v3/[^/]*/\([^/]*\)/.*|\1|p')
50
+ AZDO_ORG_URL="https://dev.azure.com/$AZDO_ORG"
51
+ elif echo "$REMOTE_URL" | grep -q 'visualstudio\.com'; then
52
+ AZDO_ORG=$(echo "$REMOTE_URL" | sed -n 's|.*//\([^.]*\)\.visualstudio\.com.*|\1|p')
53
+ AZDO_PROJECT=$(echo "$REMOTE_URL" | sed -n 's|.*/\([^/]*\)/_git/.*|\1|p')
54
+ # Preserve the original domain for REST API compatibility
55
+ AZDO_ORG_URL="https://${AZDO_ORG}.visualstudio.com"
56
+ fi
57
+
58
+ # URL-decode for CLI/display; keep URL-safe versions for REST API paths
59
+ AZDO_PROJECT_URL_SAFE="$AZDO_PROJECT"
60
+ AZDO_PROJECT=$(python3 -c "import urllib.parse; print(urllib.parse.unquote('$AZDO_PROJECT'))")
61
+
62
+ if [ -z "$AZDO_ORG" ] || [ -z "$AZDO_PROJECT" ]; then
63
+ echo "❌ Could not extract organization/project from remote URL"
64
+ echo " Remote: $REMOTE_URL"
65
+ echo ""
66
+ echo "Ensure the remote URL follows one of these formats:"
67
+ echo " https://dev.azure.com/{ORG}/{PROJECT}/_git/{REPO}"
68
+ echo " https://{ORG}.visualstudio.com/{PROJECT}/_git/{REPO}"
69
+ echo " {ORG}@vs-ssh.visualstudio.com:v3/{ORG}/{PROJECT}/{REPO}"
70
+ # HALT — cannot proceed without org/project context
71
+ fi
72
+ ```
73
+
74
+ When `AZDO_MODE == cli`, also configure the defaults so commands work correctly:
75
+ ```bash
76
+ az devops configure --defaults organization="$AZDO_ORG_URL" project="$AZDO_PROJECT"
77
+ ```
78
+
79
+ When `AZDO_MODE == rest`, store these for API calls:
80
+ - Base URL: `$AZDO_ORG_URL/$AZDO_PROJECT_URL_SAFE/_apis`
81
+ - Auth header: `Authorization: Basic $(printf ":%s" "$PAT" | base64 | tr -d '\n')`
82
+
83
+ Report in pre-flight:
84
+ - ✅ `azdo context` — org: `{AZDO_ORG}`, project: `{AZDO_PROJECT}`
85
+ - ❌ `azdo context` — could not parse from remote URL → halt with instructions
86
+
87
+ Pass `{AZDO_MODE}`, `{AZDO_ORG}`, `{AZDO_PROJECT}`, `{AZDO_ORG_URL}` into
88
+ all phase prompts alongside `{PLATFORM}`.
@@ -0,0 +1,51 @@
1
+ # Superpowers Deferral Contract
2
+
3
+ Shared deferral behavior for `speccy`, `build`, and `ship`. Superpowers is a
4
+ soft/recommended dependency (runtime-detected, like claude-mem) — never required.
5
+ When it is absent, every skill runs its standalone pipeline unchanged.
6
+
7
+ ## Detection
8
+
9
+ Detection is a bounded on-disk anchor check via `scripts/lib/superpowers.js`
10
+ (anchor file: `using-superpowers/SKILL.md`). Run it from a SKILL.md pre-flight
11
+ step with an ESM-safe dynamic import. `LIB` resolves to the plugin's
12
+ `scripts/lib` directory using the same `CLAUDE_PLUGIN_ROOT` fallback the other
13
+ skills use, so it works for plugin installs and degrades gracefully otherwise:
14
+
15
+ ```bash
16
+ LIB="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/plugins/marketplaces/slamb2k}/scripts/lib"
17
+ SP=$(node -e "import('$LIB/superpowers.js').then(m=>process.stdout.write(m.detectSuperpowers().installed?'1':'0')).catch(()=>process.stdout.write('0'))")
18
+ ```
19
+
20
+ `SP` is `1` when Superpowers is detected, `0` otherwise. If the helper is not
21
+ present at runtime (e.g. a single-skill install), the `.catch` yields `0` so the
22
+ skill safely runs its standalone pipeline. Passing `--no-superpowers`
23
+ short-circuits `SP` to `0` before this check runs.
24
+
25
+ ## Announcement format
26
+
27
+ When deferring, print exactly one line (GUD-002):
28
+
29
+ ```
30
+ ⚡ Superpowers detected — deferring {stage} to superpowers:{skill}
31
+ ```
32
+
33
+ ## `--no-superpowers` flag
34
+
35
+ Parsed alongside each skill's existing flags. Forces the standalone pipeline even
36
+ when Superpowers is installed. Treat it as setting `SP=0` for the whole run.
37
+
38
+ ## Absent-fallback rule (REQ-007)
39
+
40
+ When Superpowers is not installed (or `--no-superpowers` is set), the skill runs
41
+ its current standalone pipeline with byte-for-byte identical user-facing output.
42
+ No announcement is printed — the deferral logic is purely additive.
43
+
44
+ ## Per-skill deferral map
45
+
46
+ | Skill / stage | Defers to (when present) | Retained by mad-skills |
47
+ |---|---|---|
48
+ | `speccy` requirements interview | `superpowers:brainstorming` | writes `specs/*.md` + pending-build marker |
49
+ | `build` plan/implement core | `superpowers:executing-plans` / `superpowers:subagent-driven-development` | explore, 3× code-review, verify, ship gate |
50
+ | `ship` final integration | `superpowers:finishing-a-development-branch` | sync, branch, commit, PR, CI-poll, auto-fix |
51
+ | `prime` graphify awareness | — (hint only) | context summary |
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Shared YAML frontmatter parser for SKILL.md files.
3
+ * Used by validate-skills.js and build-manifests.js.
4
+ */
5
+
6
+ export function parseFrontmatter(content) {
7
+ // Normalise line endings (CRLF → LF) for cross-platform support
8
+ const normalised = content.replace(/\r\n/g, "\n");
9
+ const match = normalised.match(/^---\n([\s\S]*?)\n---/);
10
+ if (!match) return null;
11
+
12
+ const result = {};
13
+ let currentKey = null;
14
+ let currentValue = "";
15
+
16
+ for (const line of match[1].split("\n")) {
17
+ // Continuation line (indented)
18
+ if (currentKey && (line.startsWith(" ") || line.startsWith("\t"))) {
19
+ currentValue += " " + line.trim();
20
+ result[currentKey] = currentValue;
21
+ continue;
22
+ }
23
+
24
+ const colonIdx = line.indexOf(":");
25
+ if (colonIdx === -1) continue;
26
+
27
+ currentKey = line.slice(0, colonIdx).trim();
28
+ currentValue = line.slice(colonIdx + 1).trim();
29
+ result[currentKey] = currentValue;
30
+ }
31
+
32
+ return result;
33
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Shared Superpowers detection helper.
3
+ * Soft-dependency, on-disk anchor check — used by speccy/build/ship pre-flight.
4
+ */
5
+
6
+ import os from "node:os";
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+
10
+ const ANCHOR = "using-superpowers/SKILL.md";
11
+ const MAX_DEPTH = 7;
12
+
13
+ function anchorExists(dir) {
14
+ try {
15
+ return fs.existsSync(path.join(dir, ANCHOR));
16
+ } catch {
17
+ return false;
18
+ }
19
+ }
20
+
21
+ function findAnchorDir(root, depth = 0) {
22
+ if (depth > MAX_DEPTH) return null;
23
+
24
+ if (anchorExists(root)) return root;
25
+
26
+ let entries;
27
+ try {
28
+ entries = fs.readdirSync(root, { withFileTypes: true });
29
+ } catch {
30
+ return null;
31
+ }
32
+
33
+ for (const entry of entries) {
34
+ if (!entry.isDirectory()) continue;
35
+ const child = path.join(root, entry.name);
36
+ const hit = findAnchorDir(child, depth + 1);
37
+ if (hit) return hit;
38
+ }
39
+
40
+ return null;
41
+ }
42
+
43
+ export function detectSuperpowers({
44
+ homedir = os.homedir(),
45
+ cwd = process.cwd(),
46
+ } = {}) {
47
+ const roots = [
48
+ path.join(homedir, ".claude", "plugins"),
49
+ path.join(homedir, ".claude", "skills", "superpowers"),
50
+ path.join(cwd, ".claude", "skills"),
51
+ ];
52
+
53
+ for (const root of roots) {
54
+ const hit = findAnchorDir(root);
55
+ if (hit) {
56
+ return { installed: true, basePath: hit };
57
+ }
58
+ }
59
+
60
+ return { installed: false, basePath: null };
61
+ }
@@ -0,0 +1,76 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+
7
+ import { detectSuperpowers } from "./superpowers.js";
8
+
9
+ function mkTmp() {
10
+ return fs.mkdtempSync(path.join(os.tmpdir(), "sp-"));
11
+ }
12
+
13
+ function writeAnchor(dir, rel) {
14
+ const file = path.join(dir, rel);
15
+ fs.mkdirSync(path.dirname(file), { recursive: true });
16
+ fs.writeFileSync(file, "# anchor\n");
17
+ }
18
+
19
+ test("installed: anchor under plugins cache", () => {
20
+ const tmp = mkTmp();
21
+ try {
22
+ writeAnchor(
23
+ tmp,
24
+ ".claude/plugins/somepkg/superpowers/skills/using-superpowers/SKILL.md",
25
+ );
26
+ const result = detectSuperpowers({ homedir: tmp, cwd: tmp });
27
+ assert.equal(result.installed, true);
28
+ assert.ok(result.basePath);
29
+ } finally {
30
+ fs.rmSync(tmp, { recursive: true, force: true });
31
+ }
32
+ });
33
+
34
+ test("not installed: empty tree", () => {
35
+ const tmp = mkTmp();
36
+ try {
37
+ const result = detectSuperpowers({ homedir: tmp, cwd: tmp });
38
+ assert.equal(result.installed, false);
39
+ assert.equal(result.basePath, null);
40
+ } finally {
41
+ fs.rmSync(tmp, { recursive: true, force: true });
42
+ }
43
+ });
44
+
45
+ test("partial install: anchor missing → not installed", () => {
46
+ const tmp = mkTmp();
47
+ try {
48
+ writeAnchor(
49
+ tmp,
50
+ ".claude/plugins/somepkg/superpowers/skills/writing-plans/SKILL.md",
51
+ );
52
+ const result = detectSuperpowers({ homedir: tmp, cwd: tmp });
53
+ assert.equal(result.installed, false);
54
+ assert.equal(result.basePath, null);
55
+ } finally {
56
+ fs.rmSync(tmp, { recursive: true, force: true });
57
+ }
58
+ });
59
+
60
+ test("project-local: anchor under cwd .claude/skills", () => {
61
+ const tmp = mkTmp();
62
+ try {
63
+ writeAnchor(
64
+ tmp,
65
+ ".claude/skills/superpowers-foo/using-superpowers/SKILL.md",
66
+ );
67
+ const result = detectSuperpowers({
68
+ homedir: path.join(tmp, "nohome"),
69
+ cwd: tmp,
70
+ });
71
+ assert.equal(result.installed, true);
72
+ assert.ok(result.basePath);
73
+ } finally {
74
+ fs.rmSync(tmp, { recursive: true, force: true });
75
+ }
76
+ });
@@ -87,6 +87,7 @@ Before starting, check all dependencies in this table:
87
87
  |-----------|------|-------|----------|------------|--------|
88
88
  | claude-mem | plugin | — | no | ask | `claude plugin install claude-mem` |
89
89
  | oh-my-claudecode | plugin | — | no | ask | `claude plugin install oh-my-claudecode` |
90
+ | superpowers | plugin | on-disk glob via scripts/lib/superpowers.js | no | ask | `claude plugin install superpowers` |
90
91
 
91
92
  For each row, in order:
92
93
  1. Run the Check command (for cli/npm) or test file existence (for agent/skill)
@@ -104,6 +105,11 @@ For each row, in order:
104
105
  name set to `true`. Store results as `PLUGIN_STATE` (`claude_mem_installed`,
105
106
  `omc_installed`) for use in Phase 4 and Phase 7.
106
107
 
108
+ **Superpowers detection differs:** Superpowers is a soft dependency detected via
109
+ the on-disk glob helper `scripts/lib/superpowers.js` (anchor file
110
+ `using-superpowers/SKILL.md`), **not** the `enabledPlugins` settings.json check
111
+ used for claude-mem and OMC — see `references/superpowers-deferral.md`.
112
+
107
113
  1. Capture **FLAGS** from the user's request
108
114
 
109
115
  ---
@@ -53,6 +53,16 @@ MCP tools for search, timeline, and observation management. Claude Code's
53
53
  built-in auto memory (`~/.claude/projects/<project>/memory/MEMORY.md`)
54
54
  handles curated facts.
55
55
 
56
+ For the methodology layer (plan → build → finish), install the **superpowers**
57
+ plugin:
58
+ ```
59
+ claude plugin install superpowers
60
+ ```
61
+
62
+ mad-skills defers its overlapping `/speccy`, `/build`, and `/ship` stages to
63
+ superpowers when it is present, and falls back to its own standalone pipeline
64
+ when it is absent.
65
+
56
66
  {PLUGIN_ROLE_SEPARATION}
57
67
 
58
68
  {UNIVERSAL_PRINCIPLES}
@@ -75,6 +75,7 @@ Parse optional flags from the request:
75
75
  - `--skip-review`: Skip Stage 5 (code review)
76
76
  - `--no-ship`: Stop after Stage 8 docs update
77
77
  - `--parallel-impl`: Split implementation into parallel agents when independent
78
+ - `--no-superpowers`: Force the standalone pipeline even when Superpowers is installed
78
79
 
79
80
  ---
80
81
 
@@ -89,6 +90,7 @@ Before starting, check all dependencies in this table:
89
90
  | feature-dev:code-explorer | agent | — | no | fallback | Uses general-purpose agent |
90
91
  | feature-dev:code-architect | agent | — | no | fallback | Uses general-purpose agent |
91
92
  | feature-dev:code-reviewer | agent | — | no | fallback | Uses general-purpose agent |
93
+ | superpowers | plugin | on-disk glob via scripts/lib/superpowers.js | no | fallback | Routes Stage 4 impl core to superpowers:executing-plans / subagent-driven-development when present; see references/superpowers-deferral.md |
92
94
 
93
95
  For each row, in order:
94
96
  1. Run the Check command (for cli/npm) or test file existence (for agent/skill)
@@ -241,6 +243,16 @@ If rejected, incorporate feedback and re-run.
241
243
 
242
244
  ## Stage 4: Implementation
243
245
 
246
+ **Superpowers deferral (soft dependency):** When Superpowers is detected (per the
247
+ pre-flight check) and `--no-superpowers` is not set, announce
248
+ `⚡ Superpowers detected — deferring plan/implement core to superpowers:executing-plans`
249
+ and route the plan-execution/implementation core through
250
+ `superpowers:executing-plans` / `superpowers:subagent-driven-development` instead
251
+ of the general-purpose subagents below. Stage 1 (explore), Stage 5 (3× review),
252
+ and Stage 7 (verify) remain unchanged either way. When Superpowers is absent or
253
+ `--no-superpowers` is set, run the standalone implementation below unchanged.
254
+ See `references/superpowers-deferral.md`.
255
+
244
256
  If ARCH_REPORT identifies independent `parallel_groups`, launch **multiple
245
257
  general-purpose subagents in parallel** — one per group. Do NOT wait for
246
258
  `--parallel-impl` flag; parallel execution is the **default** when the
@@ -32,5 +32,21 @@
32
32
  { "type": "contains", "value": "██" },
33
33
  { "type": "semantic", "value": "Acknowledges the --skip-questions flag (skipping clarifying questions) and the --no-ship flag (stopping before committing/pushing/creating PR)" }
34
34
  ]
35
+ },
36
+ {
37
+ "name": "build-superpowers-present",
38
+ "prompt": "The superpowers plugin is installed. Run build on specs/rate-limiter.md. Which superpowers skill does build route its implementation core through?",
39
+ "assertions": [
40
+ { "type": "regex", "value": "(executing-plans|subagent-driven-development)", "flags": "i" },
41
+ { "type": "contains", "value": "Superpowers detected" }
42
+ ]
43
+ },
44
+ {
45
+ "name": "build-superpowers-absent",
46
+ "prompt": "Superpowers is NOT installed. How does build implement a plan?",
47
+ "assertions": [
48
+ { "type": "regex", "value": "(explore|architect|implement|review)", "flags": "i" },
49
+ { "type": "semantic", "value": "Runs the standalone feature-dev pipeline (explore, architect, implement, review, verify) using its own subagents, with no deferral to superpowers" }
50
+ ]
35
51
  }
36
52
  ]
@@ -1,12 +1,12 @@
1
1
  {
2
- "generated": "2026-04-20T03:16:08.071Z",
2
+ "generated": "2026-07-06T02:10:36.483Z",
3
3
  "count": 11,
4
4
  "skills": [
5
5
  {
6
6
  "name": "brace",
7
7
  "directory": "brace",
8
8
  "description": "'Initialize any project directory with a standard scaffold for AI-assisted development. Creates specs/ and context/ directories, a project CLAUDE.md with development workflow and guardrails, .gitignore, and branch protection. Recommends claude-mem for persistent memory. Idempotent — safe to run on existing projects. Triggers: \"init project\", \"setup brace\", \"brace\", \"initialize\", \"bootstrap\", \"scaffold\".'",
9
- "lines": 430,
9
+ "lines": 436,
10
10
  "hasScripts": false,
11
11
  "hasReferences": true,
12
12
  "hasAssets": true,
@@ -16,7 +16,7 @@
16
16
  "name": "build",
17
17
  "directory": "build",
18
18
  "description": "Context-isolated feature development pipeline. Takes a detailed design/plan as argument and executes the full feature-dev lifecycle (explore, question, architect, implement, review, ship) inside subagents so the primary conversation stays compact. Use when you have a well-defined plan and want autonomous execution with minimal context window consumption.",
19
- "lines": 456,
19
+ "lines": 468,
20
20
  "hasScripts": false,
21
21
  "hasReferences": true,
22
22
  "hasAssets": false,
@@ -66,7 +66,7 @@
66
66
  "name": "prime",
67
67
  "directory": "prime",
68
68
  "description": "\"Load project context before implementing features or making architectural decisions. Invoke proactively at the start of significant work on any project. Scans CLAUDE.md, README, specs/, docs/, and source structure to build a context summary. Supports optional domain hints to focus on specific areas of the codebase. Use when you need project conventions, architecture understanding, or domain context before coding.\"",
69
- "lines": 148,
69
+ "lines": 165,
70
70
  "hasScripts": false,
71
71
  "hasReferences": true,
72
72
  "hasAssets": false,
@@ -86,7 +86,7 @@
86
86
  "name": "ship",
87
87
  "directory": "ship",
88
88
  "description": "\"Ship changes through the full PR lifecycle. Use after completing feature work to commit, push, create PR, wait for checks, and merge. Handles the entire workflow: syncs with main, creates feature branch if needed, groups commits logically with semantic messages, creates detailed PR, monitors CI, fixes issues, squash merges, and cleans up. Invoke when work is ready to ship.\"",
89
- "lines": 495,
89
+ "lines": 499,
90
90
  "hasScripts": true,
91
91
  "hasReferences": true,
92
92
  "hasAssets": false,
@@ -96,7 +96,7 @@
96
96
  "name": "speccy",
97
97
  "directory": "speccy",
98
98
  "description": "Deep-dive interview skill for creating comprehensive specifications. Reviews existing code and docs, then interviews the user through multiple rounds of targeted questions covering technical implementation, UI/UX, concerns, and tradeoffs. Produces a structured spec in specs/. Use when starting a new feature, system, or major change that needs a spec.",
99
- "lines": 260,
99
+ "lines": 275,
100
100
  "hasScripts": false,
101
101
  "hasReferences": true,
102
102
  "hasAssets": false,
@@ -108,6 +108,13 @@ For each file:
108
108
  - If it exists: read and summarise (2-3 lines max per domain)
109
109
  - If it doesn't exist: record as NOT FOUND and continue
110
110
 
111
+ ## Graphify Awareness (existence check only)
112
+
113
+ Check whether a `graphify-out/` directory exists at the project root
114
+ (existence only — do NOT run any graphify query, read its contents, or treat
115
+ it as a dependency). Record the boolean in the report. This is purely additive:
116
+ when absent, the report is unchanged.
117
+
111
118
  ## Output Format
112
119
 
113
120
  PRIME_REPORT:
@@ -117,6 +124,7 @@ PRIME_REPORT:
117
124
  - per_domain_summary:
118
125
  - {domain}: {2-3 line summary}
119
126
  - branch: {current branch from git branch --show-current}
127
+ - graphify_out_present: {true|false}
120
128
  - ready_for: {inferred from loaded context}
121
129
  ```
122
130
 
@@ -143,5 +151,14 @@ Parse PRIME_REPORT and present a clean summary to the user:
143
151
  └─────────────────────────────────────────────────
144
152
  ```
145
153
 
154
+ If `graphify_out_present` is true, add a single passive line after the report
155
+ box (omit entirely when false):
156
+
157
+ ```
158
+ graphify-out/ detected — codebase questions can be answered via /graphify
159
+ ```
160
+
161
+ This is a hint only — never execute a graphify query on the user's behalf.
162
+
146
163
  If CLAUDE.md was missing, warn the user and note that only domain context
147
164
  was loaded.
@@ -24,5 +24,14 @@
24
24
  { "type": "contains", "value": "██" },
25
25
  { "type": "semantic", "value": "Recognizes 'dashboard' and 'routing' as valid domain-specific contexts and describes loading files relevant to those domains" }
26
26
  ]
27
+ },
28
+ {
29
+ "name": "prime-graphify-hint",
30
+ "prompt": "Prime me for this project. The repository root contains a graphify-out/ directory alongside CLAUDE.md and specs/.",
31
+ "assertions": [
32
+ { "type": "contains", "value": "██" },
33
+ { "type": "contains", "value": "/graphify" },
34
+ { "type": "semantic", "value": "Detects the graphify-out/ directory by existence only and surfaces a passive hint that codebase questions can be answered via /graphify, without running any graphify query" }
35
+ ]
27
36
  }
28
37
  ]
@@ -70,6 +70,7 @@ Parse optional flags from the request:
70
70
  - `--pr-only`: Stop after creating the PR
71
71
  - `--no-squash`: Use regular merge instead of squash
72
72
  - `--keep-branch`: Don't delete the source branch after merge
73
+ - `--no-superpowers`: Force standalone merge even when Superpowers is installed
73
74
 
74
75
  ---
75
76
 
@@ -113,6 +114,7 @@ Before starting, check all dependencies in this table. The table contains
113
114
  | git | cli | `git --version` | yes | stop | Install from https://git-scm.com |
114
115
  | gh | cli | `gh --version` | yes | url | https://cli.github.com |
115
116
  | az devops | cli | `az devops -h 2>/dev/null` | no | fallback | Falls back to REST API with PAT; see AzDO tooling below |
117
+ | superpowers | plugin | on-disk glob via scripts/lib/superpowers.js | no | fallback | Replaces final merge with superpowers:finishing-a-development-branch when present; see references/superpowers-deferral.md |
116
118
 
117
119
  **Platform-conditional rules:**
118
120
  - **`gh`**: Only required when `PLATFORM == github`. Skip for AzDO repos.
@@ -374,6 +376,8 @@ defaults (override via `--no-squash` and `--keep-branch` flags only).
374
376
 
375
377
  ### 5a. Merge the PR
376
378
 
379
+ **Superpowers deferral:** When Superpowers is detected and `--no-superpowers` is not set, after CI is green and auto-fix, announce `⚡ Superpowers detected — deferring final integration to superpowers:finishing-a-development-branch` and invoke that skill to present merge/PR/cleanup options instead of calling merge.sh directly (CI-poll + auto-fix and the no-manual-CI-trigger rule still apply); otherwise run merge.sh below.
380
+
377
381
  Run the merge script directly (no LLM needed):
378
382
 
379
383
  ```bash
@@ -26,5 +26,21 @@
26
26
  { "type": "regex", "value": "(script|sync\\.sh|ci-watch\\.sh|merge\\.sh|general.purpose)", "flags": "i" },
27
27
  { "type": "semantic", "value": "Uses deterministic scripts for sync, CI monitoring, and merge stages, with LLM subagents only for commit/PR authoring and CI fix analysis" }
28
28
  ]
29
+ },
30
+ {
31
+ "name": "ship-superpowers-present",
32
+ "prompt": "The superpowers plugin is installed. Run ship. Once CI is green, which superpowers skill handles the final integration instead of an auto squash-merge?",
33
+ "assertions": [
34
+ { "type": "contains", "value": "finishing-a-development-branch" },
35
+ { "type": "contains", "value": "Superpowers detected" }
36
+ ]
37
+ },
38
+ {
39
+ "name": "ship-superpowers-absent",
40
+ "prompt": "Superpowers is NOT installed. How does ship merge the PR after CI passes?",
41
+ "assertions": [
42
+ { "type": "regex", "value": "(squash|merge)", "flags": "i" },
43
+ { "type": "semantic", "value": "Runs the standalone merge (squash merge and delete branch by default) via merge.sh, with no deferral to superpowers" }
44
+ ]
29
45
  }
30
46
  ]
@@ -66,6 +66,11 @@ in `references/spec-template.md`.
66
66
  Interview prompts and question guidelines: `references/interview-guide.md`
67
67
  Spec template and writing guidelines: `references/spec-template.md`
68
68
 
69
+ ## Flags
70
+
71
+ Parse optional flags from the request:
72
+ - `--no-superpowers`: Force the standalone interview even when Superpowers is installed
73
+
69
74
  ## Pre-flight
70
75
 
71
76
  Before starting, check all dependencies in this table:
@@ -73,6 +78,7 @@ Before starting, check all dependencies in this table:
73
78
  | Dependency | Type | Check | Required | Resolution | Detail |
74
79
  |-----------|------|-------|----------|------------|--------|
75
80
  | prime | skill | `ls .claude/skills/prime/SKILL.md ~/.claude/skills/prime/SKILL.md ~/.claude/plugins/marketplaces/slamb2k/skills/prime/SKILL.md 2>/dev/null` | no | fallback | Context loading; falls back to manual project scan |
81
+ | superpowers | plugin | on-disk glob via scripts/lib/superpowers.js | no | fallback | Defers Stage 2 interview to superpowers:brainstorming when present; see references/superpowers-deferral.md |
76
82
 
77
83
  For each row, in order:
78
84
  1. Test file existence (check both paths for symlinked skills)
@@ -135,6 +141,15 @@ Group gaps into interview categories:
135
141
  Conduct multiple rounds of questions using `AskUserQuestion`. Continue until
136
142
  all knowledge gaps are resolved.
137
143
 
144
+ **Superpowers deferral (soft dependency):** When Superpowers is detected (per the
145
+ pre-flight check) and the `--no-superpowers` flag is not set, announce
146
+ `⚡ Superpowers detected — deferring requirements interview to superpowers:brainstorming`
147
+ and use `superpowers:brainstorming` for requirements/gap exploration in place of
148
+ (or ahead of) the multi-round interview below. In ALL cases — deferred or
149
+ standalone — speccy still writes `specs/{slug}.md` and the pending-build marker
150
+ (see `references/superpowers-deferral.md`). When Superpowers is absent or
151
+ `--no-superpowers` is set, run the standalone interview unchanged.
152
+
138
153
  ### Question Rules
139
154
 
140
155
  1. **4 questions per round maximum** (AskUserQuestion limit)
@@ -30,5 +30,29 @@
30
30
  "value": "Security"
31
31
  }
32
32
  ]
33
+ },
34
+ {
35
+ "name": "speccy-superpowers-present",
36
+ "prompt": "The superpowers plugin is installed. Run speccy to spec out a rate limiter. Which stage does speccy defer, and to which superpowers skill?",
37
+ "assertions": [
38
+ {
39
+ "type": "contains",
40
+ "value": "⚡ Superpowers detected"
41
+ },
42
+ {
43
+ "type": "contains",
44
+ "value": "brainstorming"
45
+ }
46
+ ]
47
+ },
48
+ {
49
+ "name": "speccy-superpowers-absent",
50
+ "prompt": "Superpowers is NOT installed. How does speccy gather requirements to build a spec?",
51
+ "assertions": [
52
+ {
53
+ "type": "contains",
54
+ "value": "interview"
55
+ }
56
+ ]
33
57
  }
34
58
  ]