bigpowers 2.11.0 → 2.12.1

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/.pi/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bigpowers",
3
- "version": "2.11.0",
4
- "description": "65 skills — 61 agent skills for spec-driven, test-first software development by solo developers",
3
+ "version": "2.12.1",
4
+ "description": "66 skills — 61 agent skills for spec-driven, test-first software development by solo developers",
5
5
  "keywords": [
6
6
  "pi-package"
7
7
  ],
@@ -0,0 +1,190 @@
1
+ ---
2
+ description: "Post-deploy health-check against a live URL. Validates HTTP status, response content, and critical endpoints. Runnable standalone OR as the final step of the deploy skill."
3
+ ---
4
+
5
+
6
+ # Smoke Test
7
+
8
+ > **HARD GATE** — Do NOT run smoke-test against a URL that hasn't been deployed yet. Always run `deploy` first, then `smoke-test`.
9
+ >
10
+ > **HARD GATE** — A failed smoke test means the deployment is broken. Do NOT mark a deploy as successful until all smoke checks pass.
11
+
12
+ Validate a deployed application is healthy by running a configurable set of HTTP checks against live URLs. Each check asserts:
13
+ - HTTP status code (e.g., 200 for success, 404 for expected-not-found)
14
+ - Response body content signal (regex or jq expression)
15
+ - Response time threshold (optional)
16
+
17
+ Can be run standalone for quick health checks or chained as the final step of the `deploy` skill.
18
+
19
+ ## Configuration
20
+
21
+ Smoke checks are defined in `smoke-checks.yaml` at the project root:
22
+
23
+ ```yaml
24
+ # smoke-checks.yaml — auto-loaded if present at project root
25
+ base_url: "https://example.com"
26
+ checks:
27
+ - name: "Homepage"
28
+ path: "/"
29
+ method: GET
30
+ expected_status: 200
31
+ content_signal: "bigpowers"
32
+ max_response_time_ms: 3000
33
+
34
+ - name: "API Health"
35
+ path: "/api/health"
36
+ method: GET
37
+ expected_status: 200
38
+ content_signal: "ok|healthy"
39
+
40
+ - name: "API Jogos"
41
+ path: "/api/jogos"
42
+ method: GET
43
+ expected_status: 200
44
+ content_signal: "jogos|games"
45
+
46
+ - name: "Not Found handling"
47
+ path: "/nonexistent"
48
+ method: GET
49
+ expected_status: 404
50
+ content_signal: "not found|404"
51
+ ```
52
+
53
+ Checks can also be specified inline via environment variables or CLI arguments for ad-hoc use.
54
+
55
+ ### Check Schema
56
+
57
+ | Field | Required | Default | Description |
58
+ |-------|----------|---------|-------------|
59
+ | `name` | Yes | — | Human-readable check name (used in report) |
60
+ | `path` | Yes | `/` | URL path relative to base_url |
61
+ | `method` | No | `GET` | HTTP method |
62
+ | `expected_status` | No | `200` | Expected HTTP status code |
63
+ | `content_signal` | No | — | Regex or string to find in response body |
64
+ | `max_response_time_ms` | No | — | Fail if response slower than this threshold (ms) |
65
+
66
+ ## Process
67
+
68
+ ### 1. Load smoke checks
69
+
70
+ ```bash
71
+ SMOKE_CHECKS_FILE="${SMOKE_CHECKS_FILE:-smoke-checks.yaml}"
72
+ BASE_URL="${DEPLOY_URL:-$BASE_URL}"
73
+
74
+ if [ -f "$SMOKE_CHECKS_FILE" ]; then
75
+ echo "Loaded smoke checks from $SMOKE_CHECKS_FILE"
76
+ elif [ -n "$BASE_URL" ]; then
77
+ echo "No smoke-checks.yaml found. Using single URL check against $BASE_URL"
78
+ else
79
+ echo "ERROR: No smoke-checks.yaml found and no DEPLOY_URL/BASE_URL set."
80
+ exit 1
81
+ fi
82
+ ```
83
+
84
+ ### 2. Run each check
85
+
86
+ For each check in the configuration, perform an HTTP request:
87
+
88
+ ```bash
89
+ url="${BASE_URL}${path}"
90
+ start_time=$(python3 -c 'import time; print(int(time.time() * 1000))')
91
+
92
+ # Perform the HTTP request
93
+ response=$(curl -s -o /tmp/smoke_body.txt -w "%{http_code}" "$url")
94
+ response_time=$(( $(python3 -c 'import time; print(int(time.time() * 1000))') - start_time ))
95
+ status=$response
96
+ body=$(cat /tmp/smoke_body.txt)
97
+ ```
98
+
99
+ ### 3. Assert results
100
+
101
+ ```bash
102
+ checks_passed=0
103
+ checks_failed=0
104
+ failures=""
105
+
106
+ # Assert status code
107
+ if [ "$status" -ne "${expected_status:-200}" ]; then
108
+ echo " FAIL: expected status ${expected_status} but got $status"
109
+ checks_failed=$((checks_failed + 1))
110
+ failures="${failures} - $name: HTTP $status (expected ${expected_status})\n"
111
+ else
112
+ echo " PASS: HTTP $status"
113
+ fi
114
+
115
+ # Assert content signal
116
+ if [ -n "$content_signal" ]; then
117
+ if echo "$body" | grep -qiE "$content_signal"; then
118
+ echo " PASS: body contains \"$content_signal\""
119
+ else
120
+ echo " FAIL: body does not contain \"$content_signal\""
121
+ checks_failed=$((checks_failed + 1))
122
+ failures="${failures} - $name: missing content signal \"$content_signal\"\n"
123
+ fi
124
+ fi
125
+
126
+ # Assert response time
127
+ if [ -n "$max_response_time_ms" ] && [ "$response_time" -gt "$max_response_time_ms" ]; then
128
+ echo " FAIL: response time ${response_time}ms exceeds ${max_response_time_ms}ms"
129
+ checks_failed=$((checks_failed + 1))
130
+ failures="${failures} - $name: response time ${response_time}ms (max ${max_response_time_ms}ms)\n"
131
+ fi
132
+ ```
133
+
134
+ ### 4. Generate report
135
+
136
+ ```bash
137
+ total=$((checks_passed + checks_failed))
138
+ echo ""
139
+ echo "=== Smoke Test Summary ==="
140
+ echo "Total: $total | Passed: $checks_passed | Failed: $checks_failed"
141
+
142
+ if [ "$checks_failed" -gt 0 ]; then
143
+ echo ""
144
+ echo "Failures:"
145
+ echo -e "$failures"
146
+ exit 1
147
+ else
148
+ echo "All checks passed."
149
+ exit 0
150
+ fi
151
+ ```
152
+
153
+ ## Runner script
154
+
155
+ A ready-to-use runner is provided for standalone operation:
156
+
157
+ ```bash
158
+ bash scripts/run-smoke.sh [url] [smoke-checks-file]
159
+ ```
160
+
161
+ The runner:
162
+ 1. Uses `$DEPLOY_URL`, `$SMOKE_CHECKS_FILE`, or CLI arguments
163
+ 2. Runs all defined checks
164
+ 3. Prints a pass/fail summary
165
+ 4. Exits 0 on all pass, non-zero on any failure
166
+
167
+ ## Integration with deploy skill
168
+
169
+ The `deploy` skill references `smoke-test` as its final verification step:
170
+
171
+ ```bash
172
+ # In deploy workflow — after successful deploy
173
+ DEPLOY_URL="$DEPLOY_URL" bash scripts/run-smoke.sh
174
+ ```
175
+
176
+ ## Configuration reference
177
+
178
+ | Variable | Default | Description |
179
+ |----------|---------|-------------|
180
+ | `SMOKE_CHECKS_FILE` | `smoke-checks.yaml` | Path to smoke checks YAML |
181
+ | `DEPLOY_URL` / `BASE_URL` | *(required)* | Base URL for all checks |
182
+ | `SMOKE_TIMEOUT` | `30` | Per-check timeout (seconds) |
183
+ | `SMOKE_RETRIES` | `0` | Number of retries on failure |
184
+
185
+ ## Verification
186
+
187
+ → verify: `test -f smoke-test/SKILL.md && grep -q 'name: smoke-test' smoke-test/SKILL.md && echo OK`
188
+ → verify: `grep -qi 'smoke.checks.yaml\|checklist\|expected_status\|content_signal' smoke-test/SKILL.md && echo OK`
189
+ → verify: `grep -ci 'pass\|fail\|summary\|report' smoke-test/SKILL.md | awk '{if($1>=2) print "OK"; else print "FAIL"}'`
190
+ → verify: `grep -q 'smoke-test' SKILL-INDEX.md && echo OK`
@@ -0,0 +1,192 @@
1
+ ---
2
+ name: smoke-test
3
+ description: "\"Post-deploy health-check against a live URL. Validates HTTP status, response content, and critical endpoints. Runnable standalone OR as the final step of the deploy skill.\""
4
+ model: sonnet
5
+ ---
6
+
7
+
8
+ # Smoke Test
9
+
10
+ > **HARD GATE** — Do NOT run smoke-test against a URL that hasn't been deployed yet. Always run `deploy` first, then `smoke-test`.
11
+ >
12
+ > **HARD GATE** — A failed smoke test means the deployment is broken. Do NOT mark a deploy as successful until all smoke checks pass.
13
+
14
+ Validate a deployed application is healthy by running a configurable set of HTTP checks against live URLs. Each check asserts:
15
+ - HTTP status code (e.g., 200 for success, 404 for expected-not-found)
16
+ - Response body content signal (regex or jq expression)
17
+ - Response time threshold (optional)
18
+
19
+ Can be run standalone for quick health checks or chained as the final step of the `deploy` skill.
20
+
21
+ ## Configuration
22
+
23
+ Smoke checks are defined in `smoke-checks.yaml` at the project root:
24
+
25
+ ```yaml
26
+ # smoke-checks.yaml — auto-loaded if present at project root
27
+ base_url: "https://example.com"
28
+ checks:
29
+ - name: "Homepage"
30
+ path: "/"
31
+ method: GET
32
+ expected_status: 200
33
+ content_signal: "bigpowers"
34
+ max_response_time_ms: 3000
35
+
36
+ - name: "API Health"
37
+ path: "/api/health"
38
+ method: GET
39
+ expected_status: 200
40
+ content_signal: "ok|healthy"
41
+
42
+ - name: "API Jogos"
43
+ path: "/api/jogos"
44
+ method: GET
45
+ expected_status: 200
46
+ content_signal: "jogos|games"
47
+
48
+ - name: "Not Found handling"
49
+ path: "/nonexistent"
50
+ method: GET
51
+ expected_status: 404
52
+ content_signal: "not found|404"
53
+ ```
54
+
55
+ Checks can also be specified inline via environment variables or CLI arguments for ad-hoc use.
56
+
57
+ ### Check Schema
58
+
59
+ | Field | Required | Default | Description |
60
+ |-------|----------|---------|-------------|
61
+ | `name` | Yes | — | Human-readable check name (used in report) |
62
+ | `path` | Yes | `/` | URL path relative to base_url |
63
+ | `method` | No | `GET` | HTTP method |
64
+ | `expected_status` | No | `200` | Expected HTTP status code |
65
+ | `content_signal` | No | — | Regex or string to find in response body |
66
+ | `max_response_time_ms` | No | — | Fail if response slower than this threshold (ms) |
67
+
68
+ ## Process
69
+
70
+ ### 1. Load smoke checks
71
+
72
+ ```bash
73
+ SMOKE_CHECKS_FILE="${SMOKE_CHECKS_FILE:-smoke-checks.yaml}"
74
+ BASE_URL="${DEPLOY_URL:-$BASE_URL}"
75
+
76
+ if [ -f "$SMOKE_CHECKS_FILE" ]; then
77
+ echo "Loaded smoke checks from $SMOKE_CHECKS_FILE"
78
+ elif [ -n "$BASE_URL" ]; then
79
+ echo "No smoke-checks.yaml found. Using single URL check against $BASE_URL"
80
+ else
81
+ echo "ERROR: No smoke-checks.yaml found and no DEPLOY_URL/BASE_URL set."
82
+ exit 1
83
+ fi
84
+ ```
85
+
86
+ ### 2. Run each check
87
+
88
+ For each check in the configuration, perform an HTTP request:
89
+
90
+ ```bash
91
+ url="${BASE_URL}${path}"
92
+ start_time=$(python3 -c 'import time; print(int(time.time() * 1000))')
93
+
94
+ # Perform the HTTP request
95
+ response=$(curl -s -o /tmp/smoke_body.txt -w "%{http_code}" "$url")
96
+ response_time=$(( $(python3 -c 'import time; print(int(time.time() * 1000))') - start_time ))
97
+ status=$response
98
+ body=$(cat /tmp/smoke_body.txt)
99
+ ```
100
+
101
+ ### 3. Assert results
102
+
103
+ ```bash
104
+ checks_passed=0
105
+ checks_failed=0
106
+ failures=""
107
+
108
+ # Assert status code
109
+ if [ "$status" -ne "${expected_status:-200}" ]; then
110
+ echo " FAIL: expected status ${expected_status} but got $status"
111
+ checks_failed=$((checks_failed + 1))
112
+ failures="${failures} - $name: HTTP $status (expected ${expected_status})\n"
113
+ else
114
+ echo " PASS: HTTP $status"
115
+ fi
116
+
117
+ # Assert content signal
118
+ if [ -n "$content_signal" ]; then
119
+ if echo "$body" | grep -qiE "$content_signal"; then
120
+ echo " PASS: body contains \"$content_signal\""
121
+ else
122
+ echo " FAIL: body does not contain \"$content_signal\""
123
+ checks_failed=$((checks_failed + 1))
124
+ failures="${failures} - $name: missing content signal \"$content_signal\"\n"
125
+ fi
126
+ fi
127
+
128
+ # Assert response time
129
+ if [ -n "$max_response_time_ms" ] && [ "$response_time" -gt "$max_response_time_ms" ]; then
130
+ echo " FAIL: response time ${response_time}ms exceeds ${max_response_time_ms}ms"
131
+ checks_failed=$((checks_failed + 1))
132
+ failures="${failures} - $name: response time ${response_time}ms (max ${max_response_time_ms}ms)\n"
133
+ fi
134
+ ```
135
+
136
+ ### 4. Generate report
137
+
138
+ ```bash
139
+ total=$((checks_passed + checks_failed))
140
+ echo ""
141
+ echo "=== Smoke Test Summary ==="
142
+ echo "Total: $total | Passed: $checks_passed | Failed: $checks_failed"
143
+
144
+ if [ "$checks_failed" -gt 0 ]; then
145
+ echo ""
146
+ echo "Failures:"
147
+ echo -e "$failures"
148
+ exit 1
149
+ else
150
+ echo "All checks passed."
151
+ exit 0
152
+ fi
153
+ ```
154
+
155
+ ## Runner script
156
+
157
+ A ready-to-use runner is provided for standalone operation:
158
+
159
+ ```bash
160
+ bash scripts/run-smoke.sh [url] [smoke-checks-file]
161
+ ```
162
+
163
+ The runner:
164
+ 1. Uses `$DEPLOY_URL`, `$SMOKE_CHECKS_FILE`, or CLI arguments
165
+ 2. Runs all defined checks
166
+ 3. Prints a pass/fail summary
167
+ 4. Exits 0 on all pass, non-zero on any failure
168
+
169
+ ## Integration with deploy skill
170
+
171
+ The `deploy` skill references `smoke-test` as its final verification step:
172
+
173
+ ```bash
174
+ # In deploy workflow — after successful deploy
175
+ DEPLOY_URL="$DEPLOY_URL" bash scripts/run-smoke.sh
176
+ ```
177
+
178
+ ## Configuration reference
179
+
180
+ | Variable | Default | Description |
181
+ |----------|---------|-------------|
182
+ | `SMOKE_CHECKS_FILE` | `smoke-checks.yaml` | Path to smoke checks YAML |
183
+ | `DEPLOY_URL` / `BASE_URL` | *(required)* | Base URL for all checks |
184
+ | `SMOKE_TIMEOUT` | `30` | Per-check timeout (seconds) |
185
+ | `SMOKE_RETRIES` | `0` | Number of retries on failure |
186
+
187
+ ## Verification
188
+
189
+ → verify: `test -f smoke-test/SKILL.md && grep -q 'name: smoke-test' smoke-test/SKILL.md && echo OK`
190
+ → verify: `grep -qi 'smoke.checks.yaml\|checklist\|expected_status\|content_signal' smoke-test/SKILL.md && echo OK`
191
+ → verify: `grep -ci 'pass\|fail\|summary\|report' smoke-test/SKILL.md | awk '{if($1>=2) print "OK"; else print "FAIL"}'`
192
+ → verify: `grep -q 'smoke-test' SKILL-INDEX.md && echo OK`
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [2.12.1](https://github.com/danielvm-git/bigpowers/compare/v2.12.0...v2.12.1) (2026-06-20)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **skills:** add run-smoke.sh referenced by deploy, smoke-test ([5108891](https://github.com/danielvm-git/bigpowers/commit/51088912084979df38d6bb529297b03a34a6bb66))
7
+
8
+ # [2.12.0](https://github.com/danielvm-git/bigpowers/compare/v2.11.0...v2.12.0) (2026-06-20)
9
+
10
+
11
+ ### Features
12
+
13
+ * **skills:** add smoke-test skill — post-deploy health-check validation ([f34cd76](https://github.com/danielvm-git/bigpowers/commit/f34cd765ffc267bc332b9cf2c6aca6431b004c50))
14
+
1
15
  # [2.11.0](https://github.com/danielvm-git/bigpowers/compare/v2.10.0...v2.11.0) (2026-06-20)
2
16
 
3
17
 
package/SKILL-INDEX.md CHANGED
@@ -3,8 +3,8 @@
3
3
  > **DO NOT EDIT** — This file is auto-generated by `scripts/generate-skill-index.sh`.
4
4
  > Edit `SKILL.md` source files or `skills-lock.json` instead. Run `bash scripts/sync-skills.sh` to regenerate.
5
5
 
6
- **Generated:** 2026-06-20T21:48:09Z
7
- **Skills:** 65
6
+ **Generated:** 2026-06-20T21:59:15Z
7
+ **Skills:** 66
8
8
 
9
9
  ---
10
10
 
@@ -15,11 +15,11 @@
15
15
  | Discover | 6 | `elaborate-spec, map-codebase, research-first, search-skills, survey-context, using-bigpowers` |
16
16
  | Design | 7 | `deepen-architecture, define-language, define-success, design-interface, grill-me, grill-with-docs, model-domain` |
17
17
  | Plan | 9 | `assess-impact, change-request, plan-refactor, plan-release, plan-work, run-planning, scope-work, seed-conventions, slice-tasks` |
18
- | Build | 15 | `align-grid, build-epic, craft-skill, deploy, develop-tdd, execute-plan, guard-git, hook-commits, kickoff-branch, orchestrate-project, publish-package, setup-environment, spike-prototype, wire-ci, wire-observability` |
18
+ | Build | 16 | `align-grid, build-epic, craft-skill, deploy, develop-tdd, execute-plan, guard-git, hook-commits, kickoff-branch, orchestrate-project, publish-package, setup-environment, smoke-test, spike-prototype, wire-ci, wire-observability` |
19
19
  | Verify | 12 | `audit-code, diagnose-root, enforce-first, fix-bug, inspect-quality, investigate-bug, request-review, respond-review, run-evals, trace-requirement, validate-fix, verify-work` |
20
20
  | Release | 2 | `commit-message, release-branch` |
21
21
  | Sustain | 13 | `compose-workflow, delegate-task, dispatch-agents, edit-document, evolve-skill, migrate-spec, organize-workspace, reset-baseline, session-state, simulate-agents, stocktake-skills, terse-mode, write-document` |
22
- | **TOTAL** | **64** | |
22
+ | **TOTAL** | **65** | |
23
23
 
24
24
  ---
25
25
 
@@ -61,38 +61,39 @@
61
61
  | 32 | Build | `orchestrate-project` | Meta-skill that enforces the 6-phase core loop (discover → elaborate → plan | ✅ Active |
62
62
  | 33 | Build | `publish-package` | "Package registry publishing for npm, crates.io, PyPI, and Homebrew. Verifies pr | ✅ Active |
63
63
  | 34 | Build | `setup-environment` | Pre-install dependencies and configure tools before development work begins. Use | ✅ Active |
64
- | 35 | Build | `spike-prototype` | Throw-away prototype for unknown problem spaces. Output is learning notes in spe | ✅ Active |
65
- | 36 | Build | `wire-ci` | "CI pipeline setup with pre-built templates and local validation. Generates GitH | ✅ Active |
66
- | 37 | Build | `wire-observability` | Add structured JSON logging, observability commands, and idempotent setup script | ✅ Active |
67
- | 38 | Verify | `audit-code` | Self-review checklist for the coding agent to run before dispatching a reviewer. | ✅ Active |
68
- | 39 | Verify | `diagnose-root` | Run 4-phase root cause analysis reproduce, isolate, hypothesize, verify. Use | ✅ Active |
69
- | 40 | Verify | `enforce-first` | Apply the F.I.R.S.T test quality rubric (Fast, Independent, Repeatable, Self-Val | ✅ Active |
70
- | 41 | Verify | `fix-bug` | Bug fix orchestrator active_flow fix_bug; reads specs/bugs/BUG-*.md; chains | ✅ Active |
71
- | 42 | Verify | `inspect-quality` | Interactive QA session where user reports bugs or issues conversationally, and t | ✅ Active |
72
- | 43 | Verify | `investigate-bug` | Investigate a bug or issue by exploring the codebase to find root cause, then wr | ✅ Active |
73
- | 44 | Verify | `request-review` | Dispatch a fresh reviewer agent with a clean context to critique the code after | ✅ Active |
74
- | 45 | Verify | `respond-review` | Act on a reviewer agent's feedback systematically categorize findings, apply | ✅ Active |
75
- | 46 | Verify | `run-evals` | Eval-Driven Development define capability and regression evals before buildi | ✅ Active |
76
- | 47 | Verify | `trace-requirement` | Link story IDs from specs/release-plan.yaml + epic capsule directories to the im | ✅ Active |
77
- | 48 | Verify | `validate-fix` | Prove a fix works before declaring done re-run the failing test, run the ful | ✅ Active |
78
- | 49 | Verify | `verify-work` | Multi-phase UAT gatecold-start smoke, build, typecheck, lint, tests, step-b | ✅ Active |
79
- | 50 | Release | `commit-message` | Reviews working-tree changes, then drafts a Conventional Commits title/body and | ✅ Active |
80
- | 51 | Release | `release-branch` | Make the merge/PR/keep/discard decision for a feature branch, verify coverage ga | ✅ Active |
81
- | 52 | Sustain | `compose-workflow` | Chain multiple bigpowers skills into a custom workflow recipe saved in specs/. U | ✅ Active |
82
- | 53 | Sustain | `delegate-task` | Delegate one complex task to a single subagent, review its work in two stages be | ✅ Active |
83
- | 54 | Sustain | `dispatch-agents` | Dispatch multiple subagents in parallel on independent tasks. No waiting between | ✅ Active |
84
- | 55 | Sustain | `edit-document` | Edit and improve documents by restructuring sections, improving clarity, and tig | ✅ Active |
85
- | 56 | Sustain | `evolve-skill` | Benchmark-gated skill evolution consume bigpowers-benchmark report, propose | ✅ Active |
86
- | 57 | Sustain | `migrate-spec` | Detect GSD, spec-kit, or BMAD spec artifacts and transform them into bigpowers Y | ✅ Active |
87
- | 58 | Sustain | `organize-workspace` | Scans the active workspace for disposable artifacts—logs, caches, stale build | ✅ Active |
88
- | 59 | Sustain | `reset-baseline` | Restore the project to a known clean state between agent runs or experiments. Us | ✅ Active |
89
- | 60 | Sustain | `session-state` | Track implementation decisions and progress in specs/state.yaml to prevent conte | ✅ Active |
90
- | 61 | Sustain | `simulate-agents` | Run Mock User and Auditor agents against a feature in fresh contexts before huma | ✅ Active |
91
- | 62 | Sustain | `stocktake-skills` | Sequential subagent batch audit of the bigpowers skill catalog Quick Scan (c | ✅ Active |
92
- | 63 | Sustain | `terse-mode` | Fallback ultra-compressed communication mode. Cuts token usage ~75% by dropping | ✅ Active |
93
- | 64 | Sustain | `write-document` | Write, organize, and sync high-integrity technical documents using the BMAD meth | ✅ Active |
94
-
95
- **Total: 64 active skills.**
64
+ | 35 | Build | `smoke-test` | "Post-deploy health-check against a live URL. Validates HTTP status, response co | ✅ Active |
65
+ | 36 | Build | `spike-prototype` | Throw-away prototype for unknown problem spaces. Output is learning notes in spe | ✅ Active |
66
+ | 37 | Build | `wire-ci` | "CI pipeline setup with pre-built templates and local validation. Generates GitH | ✅ Active |
67
+ | 38 | Build | `wire-observability` | Add structured JSON logging, observability commands, and idempotent setup script | ✅ Active |
68
+ | 39 | Verify | `audit-code` | Self-review checklist for the coding agent to run before dispatching a reviewer. | ✅ Active |
69
+ | 40 | Verify | `diagnose-root` | Run 4-phase root cause analysis reproduce, isolate, hypothesize, verify. Use | ✅ Active |
70
+ | 41 | Verify | `enforce-first` | Apply the F.I.R.S.T test quality rubric (Fast, Independent, Repeatable, Self-Val | ✅ Active |
71
+ | 42 | Verify | `fix-bug` | Bug fix orchestrator active_flow fix_bug; reads specs/bugs/BUG-*.md; chains | ✅ Active |
72
+ | 43 | Verify | `inspect-quality` | Interactive QA session where user reports bugs or issues conversationally, and t | ✅ Active |
73
+ | 44 | Verify | `investigate-bug` | Investigate a bug or issue by exploring the codebase to find root cause, then wr | ✅ Active |
74
+ | 45 | Verify | `request-review` | Dispatch a fresh reviewer agent with a clean context to critique the code after | ✅ Active |
75
+ | 46 | Verify | `respond-review` | Act on a reviewer agent's feedback systematically categorize findings, apply | ✅ Active |
76
+ | 47 | Verify | `run-evals` | Eval-Driven Development define capability and regression evals before buildi | ✅ Active |
77
+ | 48 | Verify | `trace-requirement` | Link story IDs from specs/release-plan.yaml + epic capsule directories to the im | ✅ Active |
78
+ | 49 | Verify | `validate-fix` | Prove a fix works before declaring done re-run the failing test, run the ful | ✅ Active |
79
+ | 50 | Verify | `verify-work` | Multi-phase UAT gate — cold-start smoke, build, typecheck, lint, tests, step-b | ✅ Active |
80
+ | 51 | Release | `commit-message` | Reviews working-tree changes, then drafts a Conventional Commits title/body and | ✅ Active |
81
+ | 52 | Release | `release-branch` | Make the merge/PR/keep/discard decision for a feature branch, verify coverage ga | ✅ Active |
82
+ | 53 | Sustain | `compose-workflow` | Chain multiple bigpowers skills into a custom workflow recipe saved in specs/. U | ✅ Active |
83
+ | 54 | Sustain | `delegate-task` | Delegate one complex task to a single subagent, review its work in two stages be | ✅ Active |
84
+ | 55 | Sustain | `dispatch-agents` | Dispatch multiple subagents in parallel on independent tasks. No waiting between | ✅ Active |
85
+ | 56 | Sustain | `edit-document` | Edit and improve documents by restructuring sections, improving clarity, and tig | ✅ Active |
86
+ | 57 | Sustain | `evolve-skill` | Benchmark-gated skill evolution consume bigpowers-benchmark report, propose | ✅ Active |
87
+ | 58 | Sustain | `migrate-spec` | Detect GSD, spec-kit, or BMAD spec artifacts and transform them into bigpowers Y | ✅ Active |
88
+ | 59 | Sustain | `organize-workspace` | Scans the active workspace for disposable artifacts—logs, caches, stale build | ✅ Active |
89
+ | 60 | Sustain | `reset-baseline` | Restore the project to a known clean state between agent runs or experiments. Us | ✅ Active |
90
+ | 61 | Sustain | `session-state` | Track implementation decisions and progress in specs/state.yaml to prevent conte | ✅ Active |
91
+ | 62 | Sustain | `simulate-agents` | Run Mock User and Auditor agents against a feature in fresh contexts before huma | ✅ Active |
92
+ | 63 | Sustain | `stocktake-skills` | Sequential subagent batch audit of the bigpowers skill catalog — Quick Scan (c | ✅ Active |
93
+ | 64 | Sustain | `terse-mode` | Fallback ultra-compressed communication mode. Cuts token usage ~75% by dropping | ✅ Active |
94
+ | 65 | Sustain | `write-document` | Write, organize, and sync high-integrity technical documents using the BMAD meth | ✅ Active |
95
+
96
+ **Total: 65 active skills.**
96
97
 
97
98
  ---
98
99
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bigpowers",
3
- "version": "2.11.0",
3
+ "version": "2.12.1",
4
4
  "description": "61 agent skills for spec-driven, test-first software development by solo developers",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -57,6 +57,7 @@ PHASE_MAP=(
57
57
  [guard-git]="Build"
58
58
  [hook-commits]="Build"
59
59
  [deploy]="Build"
60
+ [smoke-test]="Build"
60
61
  # Verify
61
62
  [verify-work]="Verify"
62
63
  [validate-fix]="Verify"
@@ -0,0 +1,233 @@
1
+ #!/usr/bin/env bash
2
+ # run-smoke.sh — Post-deploy health-check runner for smoke-test skill
3
+ # Usage: bash scripts/run-smoke.sh [url] [smoke-checks-file]
4
+ #
5
+ # Reads from smoke-checks.yaml by default. Falls back to single-URL check.
6
+ # Env vars: DEPLOY_URL, SMOKE_CHECKS_FILE, SMOKE_TIMEOUT, SMOKE_RETRIES
7
+ set -euo pipefail
8
+
9
+ SMOKE_CHECKS_FILE="${2:-${SMOKE_CHECKS_FILE:-smoke-checks.yaml}}"
10
+ BASE_URL="${1:-${DEPLOY_URL:-}}"
11
+ SMOKE_TIMEOUT="${SMOKE_TIMEOUT:-30}"
12
+ SMOKE_RETRIES="${SMOKE_RETRIES:-0}"
13
+
14
+ TMPDIR=$(mktemp -d)
15
+ trap 'rm -rf "$TMPDIR"' EXIT
16
+
17
+ checks_passed=0
18
+ checks_failed=0
19
+ failures=""
20
+
21
+ # ── 1. Load checks ──────────────────────────────────────────────────────────
22
+
23
+ run_single_url_check() {
24
+ local url="$1"
25
+ local name="${2:-URL check}"
26
+ local expected_status="${3:-200}"
27
+ local content_signal="${4:-}"
28
+
29
+ echo "[$name]"
30
+ start_time=$(python3 -c 'import time; print(int(time.time() * 1000))')
31
+ response=$(curl -s -o "$TMPDIR/body.txt" -w "%{http_code}" --max-time "$SMOKE_TIMEOUT" "$url")
32
+ response_time=$(( $(python3 -c 'import time; print(int(time.time() * 1000))') - start_time ))
33
+ status="$response"
34
+ body=$(cat "$TMPDIR/body.txt" 2>/dev/null || echo "")
35
+
36
+ # Assert status
37
+ if [ "$status" -ne "$expected_status" ]; then
38
+ echo " FAIL: HTTP $status (expected $expected_status)"
39
+ checks_failed=$((checks_failed + 1))
40
+ failures="${failures} - $name: HTTP $status (expected $expected_status)\n"
41
+ else
42
+ echo " PASS: HTTP $status"
43
+ checks_passed=$((checks_passed + 1))
44
+ fi
45
+
46
+ # Assert content signal
47
+ if [ -n "$content_signal" ]; then
48
+ if echo "$body" | grep -qiE "$content_signal"; then
49
+ echo " PASS: body matches \"$content_signal\""
50
+ else
51
+ echo " FAIL: body does not match \"$content_signal\""
52
+ checks_failed=$((checks_failed + 1))
53
+ failures="${failures} - $name: missing content signal \"$content_signal\"\n"
54
+ fi
55
+ fi
56
+
57
+ # Assert response time
58
+ if [ "$response_time" -gt 0 ]; then
59
+ echo " Time: ${response_time}ms"
60
+ fi
61
+ echo ""
62
+ }
63
+
64
+ parse_and_run_checks() {
65
+ local file="$1"
66
+ local base_url=""
67
+ local in_checks=false
68
+ local check_name="" check_path="" check_method="" check_status="" check_signal="" check_time=""
69
+
70
+ while IFS= read -r line; do
71
+ # Strip inline comments
72
+ line="${line%%#*}"
73
+ # Trim whitespace
74
+ line="${line#"${line%%[![:space:]]*}"}"
75
+ line="${line%"${line##*[![:space:]]}"}"
76
+ [ -z "$line" ] && continue
77
+
78
+ if [[ "$line" =~ ^base_url: ]]; then
79
+ base_url="${line#base_url:}"
80
+ base_url="${base_url#"${base_url%%[![:space:]]*}"}"
81
+ base_url="${base_url%"${base_url##*[![:space:]]}"}"
82
+ base_url="${base_url%\"}"
83
+ base_url="${base_url#\"}"
84
+ base_url="${base_url%\'}"
85
+ base_url="${base_url#\'}"
86
+ continue
87
+ fi
88
+
89
+ if [[ "$line" == "checks:" ]]; then
90
+ in_checks=true
91
+ check_name=""; check_path=""; check_method="GET"; check_status="200"
92
+ check_signal=""; check_time=""
93
+ continue
94
+ fi
95
+
96
+ if $in_checks; then
97
+ # Detect new check entry (dash at start of list item)
98
+ if [[ "$line" == "- name:"* ]]; then
99
+ # Run previous check if accumulated
100
+ if [ -n "$check_name" ] && [ -n "$base_url" ]; then
101
+ run_parsed_check "$base_url" "$check_name" "$check_path" "$check_status" "$check_signal"
102
+ fi
103
+ check_name="${line#- name:}"
104
+ check_name="${check_name#"${check_name%%[![:space:]]*}"}"
105
+ check_name="${check_name%\"}"; check_name="${check_name#\"}"
106
+ check_name="${check_name%\'}"; check_name="${check_name#\'}"
107
+ check_path=""; check_method="GET"; check_status="200"; check_signal=""; check_time=""
108
+ elif [[ "$line" == "name:"* ]]; then
109
+ check_name="${line#name:}"
110
+ check_name="${check_name#"${check_name%%[![:space:]]*}"}"
111
+ check_name="${check_name%\"}"; check_name="${check_name#\"}"
112
+ check_name="${check_name%\'}"; check_name="${check_name#\'}"
113
+ elif [[ "$line" == "path:"* ]]; then
114
+ check_path="${line#path:}"
115
+ check_path="${check_path#"${check_path%%[![:space:]]*}"}"
116
+ check_path="${check_path%\"}"; check_path="${check_path#\"}"
117
+ check_path="${check_path%\'}"; check_path="${check_path#\'}"
118
+ elif [[ "$line" == "method:"* ]]; then
119
+ check_method="${line#method:}"
120
+ check_method="${check_method#"${check_method%%[![:space:]]*}"}"
121
+ check_method="${check_method%\"}"; check_method="${check_method#\"}"
122
+ check_method="${check_method%\'}"; check_method="${check_method#\'}"
123
+ elif [[ "$line" == "expected_status:"* ]]; then
124
+ check_status="${line#expected_status:}"
125
+ check_status="${check_status#"${check_status%%[![:space:]]*}"}"
126
+ elif [[ "$line" == "content_signal:"* ]]; then
127
+ check_signal="${line#content_signal:}"
128
+ check_signal="${check_signal#"${check_signal%%[![:space:]]*}"}"
129
+ check_signal="${check_signal%\"}"; check_signal="${check_signal#\"}"
130
+ check_signal="${check_signal%\'}"; check_signal="${check_signal#\'}"
131
+ elif [[ "$line" == "max_response_time_ms:"* ]]; then
132
+ check_time="${line#max_response_time_ms:}"
133
+ check_time="${check_time#"${check_time%%[![:space:]]*}"}"
134
+ fi
135
+ fi
136
+ done < "$file"
137
+
138
+ # Run last check
139
+ if [ -n "$check_name" ] && [ -n "$base_url" ]; then
140
+ run_parsed_check "$base_url" "$check_name" "$check_path" "$check_status" "$check_signal"
141
+ fi
142
+ }
143
+
144
+ run_parsed_check() {
145
+ local base_url="$1" name="$2" path="$3" expected_status="$4" content_signal="$5"
146
+ local url="${base_url}${path}"
147
+
148
+ echo "[$name]"
149
+ echo " URL: $url"
150
+ start_time=$(python3 -c 'import time; print(int(time.time() * 1000))')
151
+ response=$(curl -s -o "$TMPDIR/body.txt" -w "%{http_code}" --max-time "$SMOKE_TIMEOUT" "$url" 2>/dev/null || echo "000")
152
+ response_time=$(( $(python3 -c 'import time; print(int(time.time() * 1000))') - start_time ))
153
+ status="$response"
154
+ body=$(cat "$TMPDIR/body.txt" 2>/dev/null || echo "")
155
+
156
+ # Assert status code
157
+ if [ "$status" -ne "$expected_status" ]; then
158
+ echo " FAIL: HTTP $status (expected $expected_status)"
159
+ checks_failed=$((checks_failed + 1))
160
+ failures="${failures} - $name: HTTP $status (expected $expected_status)\n"
161
+ else
162
+ echo " PASS: HTTP $status"
163
+ fi
164
+
165
+ # Assert content signal
166
+ if [ -n "$content_signal" ]; then
167
+ if echo "$body" | grep -qiE "$content_signal"; then
168
+ echo " PASS: body matches \"$content_signal\""
169
+ checks_passed=$((checks_passed + 1))
170
+ else
171
+ echo " FAIL: body does not match \"$content_signal\""
172
+ checks_failed=$((checks_failed + 1))
173
+ failures="${failures} - $name: missing content signal \"$content_signal\"\n"
174
+ fi
175
+ fi
176
+
177
+ # Assert response time
178
+ if [ -n "${check_time:-}" ] && [ "$check_time" -gt 0 ] 2>/dev/null; then
179
+ if [ "$response_time" -gt "$check_time" ]; then
180
+ echo " FAIL: ${response_time}ms exceeds ${check_time}ms max"
181
+ checks_failed=$((checks_failed + 1))
182
+ failures="${failures} - $name: response time ${response_time}ms (max ${check_time}ms)\n"
183
+ else
184
+ echo " PASS: ${response_time}ms within ${check_time}ms limit"
185
+ fi
186
+ fi
187
+
188
+ if [ "$response_time" -gt 0 ]; then
189
+ echo " Time: ${response_time}ms"
190
+ fi
191
+ echo ""
192
+ }
193
+
194
+ # ── Main dispatch ───────────────────────────────────────────────────────────
195
+
196
+ echo "=== Smoke Test Runner ==="
197
+ echo "Started at: $(date -u '+%Y-%m-%dT%H:%M:%SZ')"
198
+ echo ""
199
+
200
+ if [ -f "$SMOKE_CHECKS_FILE" ]; then
201
+ echo "Checks file: $SMOKE_CHECKS_FILE"
202
+ parse_and_run_checks "$SMOKE_CHECKS_FILE"
203
+ elif [ -n "$BASE_URL" ]; then
204
+ echo "Single URL mode: $BASE_URL"
205
+ run_single_url_check "$BASE_URL" "Baseline"
206
+ else
207
+ echo "ERROR: No smoke-checks.yaml found and no URL provided."
208
+ echo "Usage: bash scripts/run-smoke.sh [url] [smoke-checks-file]"
209
+ echo " DEPLOY_URL=http://example.com bash scripts/run-smoke.sh"
210
+ exit 2
211
+ fi
212
+
213
+ # ── Summary ──────────────────────────────────────────────────────────────────
214
+
215
+ total=$((checks_passed + checks_failed))
216
+ echo "=== Smoke Test Summary ==="
217
+ echo "Total: $total | Passed: $checks_passed | Failed: $checks_failed"
218
+ echo ""
219
+
220
+ if [ "$checks_failed" -gt 0 ]; then
221
+ echo "Failures:"
222
+ echo -e "$failures"
223
+ echo "Smoke test FAILED."
224
+ exit 1
225
+ fi
226
+
227
+ if [ "$total" -eq 0 ]; then
228
+ echo "No checks were executed."
229
+ exit 1
230
+ fi
231
+
232
+ echo "All checks passed."
233
+ exit 0
package/skills-lock.json CHANGED
@@ -266,6 +266,11 @@
266
266
  "sha256": "bda9db54dbe791b5",
267
267
  "path": "slice-tasks/SKILL.md"
268
268
  },
269
+ "smoke-test": {
270
+ "description": "\"Post-deploy health-check against a live URL. Validates HTTP status, response content, and critical endpoints. Runnable standalone OR as the final step of the deploy skill.\"",
271
+ "sha256": "402c89c31ac4fd4c",
272
+ "path": "smoke-test/SKILL.md"
273
+ },
269
274
  "spike-prototype": {
270
275
  "description": "Throw-away prototype for unknown problem spaces. Output is learning notes in specs/archive/spikes/SPIKE-<name>.md, not production code. Use when the domain or technology is unexplored, when estimates are impossible without experimentation, or when user says \"spike\", \"prototype\", or \"proof of concept\".",
271
276
  "sha256": "568e52ae1e3a9213",
@@ -0,0 +1,191 @@
1
+ ---
2
+ name: smoke-test
3
+ description: "Post-deploy health-check against a live URL. Validates HTTP status, response content, and critical endpoints. Runnable standalone OR as the final step of the deploy skill."
4
+ model: sonnet
5
+ ---
6
+
7
+ # Smoke Test
8
+
9
+ > **HARD GATE** — Do NOT run smoke-test against a URL that hasn't been deployed yet. Always run `deploy` first, then `smoke-test`.
10
+ >
11
+ > **HARD GATE** — A failed smoke test means the deployment is broken. Do NOT mark a deploy as successful until all smoke checks pass.
12
+
13
+ Validate a deployed application is healthy by running a configurable set of HTTP checks against live URLs. Each check asserts:
14
+ - HTTP status code (e.g., 200 for success, 404 for expected-not-found)
15
+ - Response body content signal (regex or jq expression)
16
+ - Response time threshold (optional)
17
+
18
+ Can be run standalone for quick health checks or chained as the final step of the `deploy` skill.
19
+
20
+ ## Configuration
21
+
22
+ Smoke checks are defined in `smoke-checks.yaml` at the project root:
23
+
24
+ ```yaml
25
+ # smoke-checks.yaml — auto-loaded if present at project root
26
+ base_url: "https://example.com"
27
+ checks:
28
+ - name: "Homepage"
29
+ path: "/"
30
+ method: GET
31
+ expected_status: 200
32
+ content_signal: "bigpowers"
33
+ max_response_time_ms: 3000
34
+
35
+ - name: "API Health"
36
+ path: "/api/health"
37
+ method: GET
38
+ expected_status: 200
39
+ content_signal: "ok|healthy"
40
+
41
+ - name: "API Jogos"
42
+ path: "/api/jogos"
43
+ method: GET
44
+ expected_status: 200
45
+ content_signal: "jogos|games"
46
+
47
+ - name: "Not Found handling"
48
+ path: "/nonexistent"
49
+ method: GET
50
+ expected_status: 404
51
+ content_signal: "not found|404"
52
+ ```
53
+
54
+ Checks can also be specified inline via environment variables or CLI arguments for ad-hoc use.
55
+
56
+ ### Check Schema
57
+
58
+ | Field | Required | Default | Description |
59
+ |-------|----------|---------|-------------|
60
+ | `name` | Yes | — | Human-readable check name (used in report) |
61
+ | `path` | Yes | `/` | URL path relative to base_url |
62
+ | `method` | No | `GET` | HTTP method |
63
+ | `expected_status` | No | `200` | Expected HTTP status code |
64
+ | `content_signal` | No | — | Regex or string to find in response body |
65
+ | `max_response_time_ms` | No | — | Fail if response slower than this threshold (ms) |
66
+
67
+ ## Process
68
+
69
+ ### 1. Load smoke checks
70
+
71
+ ```bash
72
+ SMOKE_CHECKS_FILE="${SMOKE_CHECKS_FILE:-smoke-checks.yaml}"
73
+ BASE_URL="${DEPLOY_URL:-$BASE_URL}"
74
+
75
+ if [ -f "$SMOKE_CHECKS_FILE" ]; then
76
+ echo "Loaded smoke checks from $SMOKE_CHECKS_FILE"
77
+ elif [ -n "$BASE_URL" ]; then
78
+ echo "No smoke-checks.yaml found. Using single URL check against $BASE_URL"
79
+ else
80
+ echo "ERROR: No smoke-checks.yaml found and no DEPLOY_URL/BASE_URL set."
81
+ exit 1
82
+ fi
83
+ ```
84
+
85
+ ### 2. Run each check
86
+
87
+ For each check in the configuration, perform an HTTP request:
88
+
89
+ ```bash
90
+ url="${BASE_URL}${path}"
91
+ start_time=$(python3 -c 'import time; print(int(time.time() * 1000))')
92
+
93
+ # Perform the HTTP request
94
+ response=$(curl -s -o /tmp/smoke_body.txt -w "%{http_code}" "$url")
95
+ response_time=$(( $(python3 -c 'import time; print(int(time.time() * 1000))') - start_time ))
96
+ status=$response
97
+ body=$(cat /tmp/smoke_body.txt)
98
+ ```
99
+
100
+ ### 3. Assert results
101
+
102
+ ```bash
103
+ checks_passed=0
104
+ checks_failed=0
105
+ failures=""
106
+
107
+ # Assert status code
108
+ if [ "$status" -ne "${expected_status:-200}" ]; then
109
+ echo " FAIL: expected status ${expected_status} but got $status"
110
+ checks_failed=$((checks_failed + 1))
111
+ failures="${failures} - $name: HTTP $status (expected ${expected_status})\n"
112
+ else
113
+ echo " PASS: HTTP $status"
114
+ fi
115
+
116
+ # Assert content signal
117
+ if [ -n "$content_signal" ]; then
118
+ if echo "$body" | grep -qiE "$content_signal"; then
119
+ echo " PASS: body contains \"$content_signal\""
120
+ else
121
+ echo " FAIL: body does not contain \"$content_signal\""
122
+ checks_failed=$((checks_failed + 1))
123
+ failures="${failures} - $name: missing content signal \"$content_signal\"\n"
124
+ fi
125
+ fi
126
+
127
+ # Assert response time
128
+ if [ -n "$max_response_time_ms" ] && [ "$response_time" -gt "$max_response_time_ms" ]; then
129
+ echo " FAIL: response time ${response_time}ms exceeds ${max_response_time_ms}ms"
130
+ checks_failed=$((checks_failed + 1))
131
+ failures="${failures} - $name: response time ${response_time}ms (max ${max_response_time_ms}ms)\n"
132
+ fi
133
+ ```
134
+
135
+ ### 4. Generate report
136
+
137
+ ```bash
138
+ total=$((checks_passed + checks_failed))
139
+ echo ""
140
+ echo "=== Smoke Test Summary ==="
141
+ echo "Total: $total | Passed: $checks_passed | Failed: $checks_failed"
142
+
143
+ if [ "$checks_failed" -gt 0 ]; then
144
+ echo ""
145
+ echo "Failures:"
146
+ echo -e "$failures"
147
+ exit 1
148
+ else
149
+ echo "All checks passed."
150
+ exit 0
151
+ fi
152
+ ```
153
+
154
+ ## Runner script
155
+
156
+ A ready-to-use runner is provided for standalone operation:
157
+
158
+ ```bash
159
+ bash scripts/run-smoke.sh [url] [smoke-checks-file]
160
+ ```
161
+
162
+ The runner:
163
+ 1. Uses `$DEPLOY_URL`, `$SMOKE_CHECKS_FILE`, or CLI arguments
164
+ 2. Runs all defined checks
165
+ 3. Prints a pass/fail summary
166
+ 4. Exits 0 on all pass, non-zero on any failure
167
+
168
+ ## Integration with deploy skill
169
+
170
+ The `deploy` skill references `smoke-test` as its final verification step:
171
+
172
+ ```bash
173
+ # In deploy workflow — after successful deploy
174
+ DEPLOY_URL="$DEPLOY_URL" bash scripts/run-smoke.sh
175
+ ```
176
+
177
+ ## Configuration reference
178
+
179
+ | Variable | Default | Description |
180
+ |----------|---------|-------------|
181
+ | `SMOKE_CHECKS_FILE` | `smoke-checks.yaml` | Path to smoke checks YAML |
182
+ | `DEPLOY_URL` / `BASE_URL` | *(required)* | Base URL for all checks |
183
+ | `SMOKE_TIMEOUT` | `30` | Per-check timeout (seconds) |
184
+ | `SMOKE_RETRIES` | `0` | Number of retries on failure |
185
+
186
+ ## Verification
187
+
188
+ → verify: `test -f smoke-test/SKILL.md && grep -q 'name: smoke-test' smoke-test/SKILL.md && echo OK`
189
+ → verify: `grep -qi 'smoke.checks.yaml\|checklist\|expected_status\|content_signal' smoke-test/SKILL.md && echo OK`
190
+ → verify: `grep -ci 'pass\|fail\|summary\|report' smoke-test/SKILL.md | awk '{if($1>=2) print "OK"; else print "FAIL"}'`
191
+ → verify: `grep -q 'smoke-test' SKILL-INDEX.md && echo OK`