@kennethsolomon/shipkit 3.1.0 → 3.2.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/README.md CHANGED
@@ -204,6 +204,7 @@ Requirement changes → /sk:change → re-enter at correct step
204
204
  | `/sk:test` | Auto-detect and run all test suites, verify 100% coverage on new code |
205
205
  | `/sk:security-check` | OWASP security audit across changed code |
206
206
  | `/sk:perf` | Performance audit: bundle size, N+1 queries, Core Web Vitals |
207
+ | `/sk:seo-audit` | SEO audit — dual-mode (source templates + dev server), ask-before-fix, checklist output to `tasks/seo-findings.md` |
207
208
  | `/sk:review` | Rigorous self-review across 7 dimensions |
208
209
 
209
210
  ### Shipping
@@ -108,7 +108,7 @@ Detect the project stack from `CLAUDE.md`, `package.json`, `composer.json`, `pyp
108
108
 
109
109
  ## Generate Report
110
110
 
111
- Write findings to `tasks/security-findings.md` using this format:
111
+ Write findings to `tasks/security-findings.md` using this format. **Never overwrite** `tasks/security-findings.md` — append new audits with a date header. Old run checkboxes stay as-is (audit trail); only update findings from the current run.
112
112
 
113
113
  ```markdown
114
114
  # Security Audit — YYYY-MM-DD
@@ -119,42 +119,43 @@ Write findings to `tasks/security-findings.md` using this format:
119
119
 
120
120
  ## Critical (must fix before deploy)
121
121
 
122
- - **[FILE:LINE]** Description of vulnerability
122
+ - [ ] **[FILE:LINE]** Description of vulnerability
123
123
  **Standard:** OWASP A03 — Injection (CWE-89)
124
124
  **Risk:** What could happen if exploited
125
125
  **Recommendation:** How to fix it
126
+ - [x] **[FILE:LINE]** Description *(resolved)*
126
127
 
127
128
  ## High (fix before production)
128
129
 
129
- - **[FILE:LINE]** Description
130
+ - [ ] **[FILE:LINE]** Description
130
131
  **Standard:** ...
131
132
  **Risk:** ...
132
133
  **Recommendation:** ...
133
134
 
134
135
  ## Medium (should fix)
135
136
 
136
- - **[FILE:LINE]** Description
137
+ - [ ] **[FILE:LINE]** Description
137
138
  **Standard:** ...
138
139
  **Recommendation:** ...
139
140
 
140
141
  ## Low / Informational
141
142
 
142
- - **[FILE:LINE]** Description
143
+ - [ ] **[FILE:LINE]** Description
143
144
  **Recommendation:** ...
144
145
 
145
146
  ## Passed Checks
146
147
 
147
- - List of categories that passed with no findings
148
+ - [Categories with no findings]
148
149
 
149
150
  ## Summary
150
151
 
151
- | Severity | Count |
152
- |----------|-------|
153
- | Critical | N |
154
- | High | N |
155
- | Medium | N |
156
- | Low | N |
157
- | **Total** | **N** |
152
+ | Severity | Open | Resolved this run |
153
+ |----------|------|-------------------|
154
+ | Critical | N | N |
155
+ | High | N | N |
156
+ | Medium | N | N |
157
+ | Low | N | N |
158
+ | **Total** | **N** | **N** |
158
159
  ```
159
160
 
160
161
  ## When Done
@@ -162,12 +163,12 @@ Write findings to `tasks/security-findings.md` using this format:
162
163
  Tell the user:
163
164
 
164
165
  > "Security audit complete. Findings saved to `tasks/security-findings.md`.
165
- > - **Critical:** N | **High:** N | **Medium:** N | **Low:** N
166
+ > - **Critical:** N open (N resolved) | **High:** N open (N resolved) | **Medium:** N open | **Low:** N open
166
167
  >
167
168
  > Review the findings, then run `/sk:finish-feature` when ready to finalize."
168
169
 
169
170
  If there are Critical or High findings:
170
- > "There are critical/high findings that should be addressed before merging. Fix them, then re-run `/sk:security-check` to verify."
171
+ > "There are critical/high findings that MUST be fixed before merging. These are HARD GATE items — `- [ ]` findings block all forward progress. Fix them, then re-run `/sk:security-check` to verify."
171
172
 
172
173
  **Do not auto-fix.** The user decides what to address.
173
174
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kennethsolomon/shipkit",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "A structured workflow toolkit for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",
@@ -89,20 +89,25 @@ Write findings to `tasks/accessibility-findings.md`:
89
89
 
90
90
  ## Failures (must fix)
91
91
 
92
- - **[Component/File:Line]** Description
92
+ - [ ] **[Component/File:Line]** Description
93
+ **Criterion:** WCAG X.X.X — [Name]
94
+ **Impact:** [Who is affected and how]
95
+ **Recommendation:** [How to fix]
96
+
97
+ - [x] **[Component/File:Line]** Description *(resolved)*
93
98
  **Criterion:** WCAG X.X.X — [Name]
94
99
  **Impact:** [Who is affected and how]
95
100
  **Recommendation:** [How to fix]
96
101
 
97
102
  ## Warnings (should fix)
98
103
 
99
- - **[Component/File:Line]** Description
104
+ - [ ] **[Component/File:Line]** Description
100
105
  **Criterion:** WCAG X.X.X — [Name]
101
106
  **Recommendation:** [How to fix]
102
107
 
103
108
  ## Manual Checks Required
104
109
 
105
- - [Things that require human/screen reader testing]
110
+ - [ ] [Things that require human/screen reader testing]
106
111
 
107
112
  ## Passed Checks
108
113
 
@@ -110,11 +115,11 @@ Write findings to `tasks/accessibility-findings.md`:
110
115
 
111
116
  ## Summary
112
117
 
113
- | Level | Count |
114
- |----------|-------|
115
- | Failures | N |
116
- | Warnings | N |
117
- | Manual | N |
118
+ | Level | Open | Resolved this run |
119
+ |----------|------|-------------------|
120
+ | Failures | N | N |
121
+ | Warnings | N | N |
122
+ | Manual | N | N |
118
123
  ```
119
124
 
120
125
  **Never overwrite** `tasks/accessibility-findings.md` — append new audits with a date header.
@@ -120,24 +120,25 @@ Write findings to `tasks/perf-findings.md`:
120
120
 
121
121
  ## Critical
122
122
 
123
- - **[FILE:LINE]** Description
123
+ - [ ] **[FILE:LINE]** Description
124
124
  **Impact:** What happens at scale
125
125
  **Recommendation:** How to fix
126
+ - [x] **[FILE:LINE]** Description *(resolved)*
126
127
 
127
128
  ## High
128
129
 
129
- - **[FILE:LINE]** Description
130
+ - [ ] **[FILE:LINE]** Description
130
131
  **Impact:** ...
131
132
  **Recommendation:** ...
132
133
 
133
134
  ## Medium
134
135
 
135
- - **[FILE:LINE]** Description
136
+ - [ ] **[FILE:LINE]** Description
136
137
  **Recommendation:** ...
137
138
 
138
139
  ## Low
139
140
 
140
- - **[FILE:LINE]** Description
141
+ - [ ] **[FILE:LINE]** Description
141
142
  **Recommendation:** ...
142
143
 
143
144
  ## Passed Checks
@@ -146,13 +147,13 @@ Write findings to `tasks/perf-findings.md`:
146
147
 
147
148
  ## Summary
148
149
 
149
- | Severity | Count |
150
- |----------|-------|
151
- | Critical | N |
152
- | High | N |
153
- | Medium | N |
154
- | Low | N |
155
- | **Total** | **N** |
150
+ | Severity | Open | Resolved this run |
151
+ |----------|------|-------------------|
152
+ | Critical | N | N |
153
+ | High | N | N |
154
+ | Medium | N | N |
155
+ | Low | N | N |
156
+ | **Total** | **N** | **N** |
156
157
  ```
157
158
 
158
159
  **Never overwrite** `tasks/perf-findings.md` — append new audits with a date header.
@@ -0,0 +1,283 @@
1
+ ---
2
+ name: sk:seo-audit
3
+ description: "SEO audit for web projects. Dual-mode: scans source templates + optionally fetches from running dev server. Ask-before-fix for mechanical issues. Outputs checklist findings to tasks/seo-findings.md."
4
+ license: Complete terms in LICENSE.txt
5
+ ---
6
+
7
+ # /sk:seo-audit
8
+
9
+ ## Purpose
10
+
11
+ Standalone optional command — audits any web project for SEO issues regardless of framework (Laravel, Next.js, Nuxt, plain HTML, etc.). Run at any point after implementation is complete. NOT a numbered workflow step — invoke it independently like `/sk:debug`.
12
+
13
+ Two modes:
14
+ - **Source mode** (always runs): scans template files directly for SEO signals
15
+ - **Server mode** (optional): fetches from a running dev server to validate rendered output
16
+
17
+ Run when: before shipping a client site, after adding new pages, or any time you want to check SEO health.
18
+
19
+ ## Hard Rules
20
+
21
+ - **Never auto-apply fixes without explicit user confirmation.**
22
+ - **Every finding must cite a specific `file:line`.**
23
+ - **Every finding is a checkbox:** `- [ ]` (open) or `- [x]` (auto-fixed this run)
24
+ - **Append to `tasks/seo-findings.md`** — never overwrite (use date header per run)
25
+ - **Degrade gracefully** if no server is running — skip Phase 2, note it in report
26
+ - **Structured data validation requires external tools** (Google Rich Results Test) — flag it, don't skip silently
27
+
28
+ ## Before You Start
29
+
30
+ 1. Read `tasks/findings.md` if it exists — look for site context, target audience, business type (helps tailor content strategy recommendations)
31
+ 2. Read `tasks/lessons.md` if it exists — apply any SEO-related lessons
32
+ 3. Check if `tasks/seo-findings.md` exists — if yes, read the last dated section to identify previously flagged items (used to populate "Passed Checks" in the new report)
33
+
34
+ ## Mode Detection
35
+
36
+ ### Source Mode — Always Active
37
+
38
+ Scan the project for template files:
39
+
40
+ | Extension | Framework |
41
+ |-----------|-----------|
42
+ | `.blade.php` | Laravel |
43
+ | `.jsx`, `.tsx` | React / Next.js |
44
+ | `.vue` | Vue / Nuxt |
45
+ | `.html` | Plain HTML / static |
46
+ | `.ejs` | Express / Node |
47
+ | `.njk` | Nunjucks |
48
+ | `.twig` | Twig / Symfony |
49
+ | `.erb` | Ruby on Rails |
50
+ | `.astro` | Astro |
51
+
52
+ Print: `"Source mode: found N template files ([extensions detected])"`
53
+
54
+ ### Server Mode — Optional
55
+
56
+ Probe ports in parallel (background curl processes) to avoid 14-second worst-case serial timeout:
57
+ - Ports: 3000, 5173, 8000, 8080, 4321, 4000, 8888
58
+ - Command: `curl -s -I --max-time 2 http://localhost:PORT` (HEAD request to capture both status code and headers)
59
+ - Use the first port that returns HTTP 200 **and** has a `Content-Type: text/html` response header
60
+
61
+ If a port returns 200 but no `Content-Type: text/html` header, skip it — it is likely a non-HTTP service (e.g., a database, gRPC server) and not a web app. Try the next port.
62
+
63
+ If any port qualifies: `"Server mode: detected running dev server at http://localhost:PORT"`
64
+
65
+ If none respond or qualify: `"Server mode: no dev server detected — skipping Phase 2. Start your dev server and re-run for full audit."`
66
+
67
+ > Note: confirm the detected URL looks correct before trusting Phase 2 results.
68
+
69
+ ## Phase 1 — Source Audit
70
+
71
+ ### Technical SEO
72
+
73
+ - `robots.txt` — exists in project root or `public/`; does NOT contain `Disallow: /` blocking all crawlers
74
+ - `sitemap.xml` — exists in project root or `public/`; referenced in `robots.txt` via `Sitemap:` directive
75
+ - `<html lang="">` — present on all layout/root templates (not empty)
76
+ - Canonical tags — `<link rel="canonical">` present on key page templates
77
+ - No accidental `<meta name="robots" content="noindex">` on public-facing pages
78
+ - No hardcoded `http://` asset URLs in templates (mixed content risk)
79
+
80
+ ### On-Page SEO
81
+
82
+ - `<title>` — present in `<head>`, unique across pages, 50–60 characters
83
+ - `<meta name="description">` — present in `<head>`, unique across pages, 150–160 characters
84
+ - Exactly one `<h1>` per page template (not zero, not two+)
85
+ - Heading hierarchy not skipped (no jumping from `<h2>` to `<h4>`)
86
+ - All `<img>` tags have `alt` attribute (even if empty for decorative — but flag empty alt on non-decorative images)
87
+ - Internal `<a>` link text is descriptive — flag anchors with text: "click here", "here", "read more", "link", "this"
88
+ - Image filenames are descriptive — flag patterns like `img001`, `IMG_`, `photo`, `image`, `DSC_`, `screenshot` with no context
89
+
90
+ ### Content Signals
91
+
92
+ - Open Graph tags: `og:title`, `og:description`, `og:url`, `og:image` all present in layout
93
+ - Twitter Card tags: `twitter:card` present
94
+ - JSON-LD structured data block: look for `<script type="application/ld+json">` — note presence/absence; do NOT validate schema (requires external tool)
95
+ - Page `<html lang="">` matches expected locale
96
+
97
+ ## Phase 2 — Server Audit (Optional)
98
+
99
+ If server detected:
100
+
101
+ 1. Fetch `/` and discover up to 4 additional pages (from `<a>` href values in homepage, or from sitemap.xml)
102
+ 2. For each page fetched, extract and compare:
103
+ - Rendered `<title>` vs source template value
104
+ - Rendered `<meta name="description">` vs source template value
105
+ - Rendered `<h1>` vs source template value
106
+ - Rendered OG tags vs source template
107
+ 3. Flag mismatches: `"/about — Source template declares <title>About Us</title> but rendered output shows <title>My App</title> — framework may be overriding"`
108
+ 4. Check HTTP status codes — flag any key page returning non-200
109
+ 5. Check for redirect chains on common pages (/ → /home → /index is a chain)
110
+
111
+ > Note in report: "Structured data detected but NOT validated — use Google Rich Results Test (https://search.google.com/test/rich-results) to verify schema markup."
112
+
113
+ ## Phase 3 — Ask Before Fix
114
+
115
+ After completing Phase 1 (and Phase 2 if run):
116
+
117
+ 1. Collect all auto-fixable findings (see Mechanical Fixes Reference below)
118
+ 2. Display numbered list:
119
+
120
+ ```
121
+ Found N auto-fixable issues:
122
+ 1. Missing <title> in resources/views/layouts/app.blade.php
123
+ 2. Missing alt attribute on <img> in resources/views/home.blade.php:42
124
+ 3. Missing robots.txt
125
+ ... (all N items)
126
+
127
+ Apply mechanical fixes? [y/N]
128
+ ```
129
+
130
+ 3. Wait for user response
131
+ 4. On `y`: apply each fix in order, log `"Fixed: [description] in [file:line]"`, mark as `- [x]` in report. On individual fix failure: log the error, mark that item `- [ ]`, and continue with remaining fixes.
132
+ 5. On `n`: mark all as `- [ ]` in report with Fix instructions
133
+
134
+ ## Mechanical Fixes Reference
135
+
136
+ What this skill CAN auto-apply when user confirms:
137
+
138
+ | Issue | Fix Applied |
139
+ |-------|------------|
140
+ | Missing `<title>` in `<head>` | Add `<title>TODO: Add page title (50-60 chars)</title>` |
141
+ | Missing `<meta name="description">` | Add `<meta name="description" content="TODO: Add description (150-160 chars)">` |
142
+ | `<img>` missing `alt` attribute | Add `alt="TODO: Describe this image for screen readers"` |
143
+ | Missing `<link rel="canonical">` | Add `<link rel="canonical" href="TODO: Add canonical URL">` |
144
+ | Missing `robots.txt` | Create `robots.txt`: `User-agent: *\nAllow: /\nSitemap: /sitemap.xml` |
145
+ | Missing `sitemap.xml` | Create `sitemap.xml` scaffold with homepage entry |
146
+ | Multiple `<h1>` on same page | Demote 2nd, 3rd... `<h1>` to `<h2>` |
147
+ | Missing OG tags | Add `og:title`, `og:description`, `og:url` block (with TODO placeholders) |
148
+ | Missing `<html lang="">` | Add `lang="en"` — **note in output: verify correct language code** |
149
+
150
+ Things this skill CANNOT auto-apply (report only):
151
+ - Content quality improvements
152
+ - Keyword targeting
153
+ - Title/description CONTENT (only adds TODOs)
154
+ - Schema markup content (only flags missing)
155
+ - Backlink strategy
156
+ - `<meta name="robots" content="noindex">` removal — only the developer can confirm whether a page is intentionally noindexed
157
+
158
+ ## Generate Report
159
+
160
+ Write to `tasks/seo-findings.md` — append with date header, never overwrite.
161
+
162
+ ```markdown
163
+ # SEO Audit — YYYY-MM-DD
164
+
165
+ **Mode:** Source only | Source + Server (`http://localhost:PORT`)
166
+ **Templates scanned:** N files ([detected extensions])
167
+ **Pages fetched:** N | none — server not detected
168
+
169
+ ---
170
+
171
+ ## Critical
172
+
173
+ - [x] `resources/views/layouts/app.blade.php` — Missing `<title>` tag *(auto-fixed — add real title)*
174
+ - [ ] `resources/views/about.blade.php:1` — Missing `<meta name="description">`
175
+ **Impact:** Google may auto-generate a description from page content, often poorly.
176
+ **Fix:** Add `<meta name="description" content="150-160 char description">` in `<head>`
177
+
178
+ ## High
179
+
180
+ - [ ] `public/robots.txt` — File missing
181
+ **Impact:** Search engines have no crawl guidance — may index unwanted pages.
182
+ **Fix:** Create `robots.txt` with `User-agent: *`, `Allow: /`, `Sitemap:` directive
183
+
184
+ ## Medium
185
+
186
+ - [ ] `resources/views/home.blade.php:42` — `<img src="hero.jpg">` missing alt attribute
187
+ **Impact:** Accessibility violation + missed keyword opportunity.
188
+ **Fix:** Add descriptive `alt="..."` text
189
+
190
+ ## Low
191
+
192
+ - [ ] Image filename `IMG_4521.jpg` — not descriptive
193
+ **Impact:** Minor missed keyword signal.
194
+ **Fix:** Rename to describe the image content
195
+
196
+ ## Content Strategy — Manual Action
197
+
198
+ - [ ] No JSON-LD structured data detected — consider adding schema markup (Article / Product / LocalBusiness / FAQPage) based on your content type. Validate at: https://search.google.com/test/rich-results
199
+ - [ ] `og:image` missing — social shares will have no preview image. Add a default OG image in your layout.
200
+ - [ ] Submit `sitemap.xml` to Google Search Console for faster indexing
201
+ - [ ] Title tags are present but content is generic ("TODO") — research target keywords for each page
202
+
203
+ ## Passed Checks
204
+
205
+ - `robots.txt` exists and allows crawling *(was: missing — fixed in 2026-03-10 audit)*
206
+ - All `<img>` tags have alt attributes
207
+ - Single `<h1>` per page
208
+
209
+ (or "First run — no prior baseline to compare against")
210
+
211
+ ## Applied Fixes
212
+
213
+ - Fixed: Added `<title>` placeholder to `resources/views/layouts/app.blade.php`
214
+ - Fixed: Created `public/robots.txt`
215
+
216
+ (or "No fixes applied this run")
217
+
218
+ ---
219
+
220
+ ## Summary
221
+
222
+ | Severity | Open | Fixed this run |
223
+ |----------|------|----------------|
224
+ | Critical | 1 | 1 |
225
+ | High | 1 | 0 |
226
+ | Medium | 3 | 0 |
227
+ | Low | 2 | 0 |
228
+ | Content Strategy | 4 | — |
229
+ | **Total** | **11** | **1** |
230
+ ```
231
+
232
+ **Never overwrite** `tasks/seo-findings.md` — append new audits with a date header.
233
+
234
+ ## When Done
235
+
236
+ If Critical or High items are open:
237
+ > "SEO audit complete. **N critical/high issues** need attention before this site will rank well. Findings and checklist in `tasks/seo-findings.md`."
238
+
239
+ If only Medium/Low/Content Strategy open:
240
+ > "Technical SEO is solid. **N medium/low polish items** and **N content strategy items** noted in `tasks/seo-findings.md`. Check off items as you address them."
241
+
242
+ If all clean:
243
+ > "SEO audit passed — no issues found. `tasks/seo-findings.md` updated with clean baseline."
244
+
245
+ If fixes were declined (`n`):
246
+ > "SEO audit complete. **N auto-fixable issues** left open (fixes declined). Checklist in `tasks/seo-findings.md` — check off items as you manually address them."
247
+
248
+ ---
249
+
250
+ ## Fix & Retest Protocol
251
+
252
+ When applying an SEO fix, classify it before committing:
253
+
254
+ **a. Template/config change** (adding a meta tag, fixing alt text, scaffolding robots.txt, adding lang attribute, creating sitemap.xml) → commit and re-run `/sk:seo-audit`. No test update needed.
255
+
256
+ **b. Logic change** (changing how a framework generates meta tags, modifying a layout component's data-fetching or rendering logic, changing routing that affects canonical URLs) → trigger protocol:
257
+ 1. Update or add failing unit tests for the new behavior
258
+ 2. Re-run `/sk:test` — must pass at 100% coverage
259
+ 3. Commit (tests + fix together in one commit)
260
+ 4. Re-run `/sk:seo-audit` to verify the fix resolved the finding
261
+
262
+ **Common logic-change SEO fixes:**
263
+ - Changing a Next.js `generateMetadata()` function → update tests asserting metadata output
264
+ - Modifying a Laravel controller that sets page title → update feature tests
265
+ - Changing a Vue component that injects `<head>` tags → update component tests
266
+
267
+ ---
268
+
269
+ ## Model Routing
270
+
271
+ Read `.shipkit/config.json` from the project root if it exists.
272
+
273
+ - If `model_overrides["sk:seo-audit"]` is set, use that model — it takes precedence.
274
+ - Otherwise use the `profile` field. Default: `balanced`.
275
+
276
+ | Profile | Model |
277
+ |---------|-------|
278
+ | `full-sail` | sonnet |
279
+ | `quality` | sonnet |
280
+ | `balanced` | sonnet |
281
+ | `budget` | haiku |
282
+
283
+ > `opus` = inherit (uses the current session model). When spawning sub-agents via the Agent tool, pass `model: "<resolved-model>"`.