specrails-core 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,405 @@
1
+ ---
2
+ name: "VPC Persona Drift Detector"
3
+ description: "Detect when user personas defined in the VPC are drifting from actual usage patterns. Compares persona Jobs/Pains/Gains against the product backlog, implemented features, and agent memory to surface alignment gaps and recommend VPC updates."
4
+ category: Product
5
+ tags: [product, vpc, personas, drift, alignment]
6
+ ---
7
+
8
+ Analyze **{{PROJECT_NAME}}** for VPC persona drift — gaps between what persona definitions promise and what the product actually delivers. Produces a per-persona alignment score, drifted attributes, and concrete VPC update recommendations.
9
+
10
+ **Input:** $ARGUMENTS — optional flags:
11
+ - `--persona <names>` — comma-separated persona names to analyze. Default: all personas.
12
+ - `--verbose` — show full attribute lists in output (default: summarized).
13
+ - `--format json` — emit the drift report as JSON instead of Markdown.
14
+
15
+ ---
16
+
17
+ ## Phase 0: Argument Parsing
18
+
19
+ Parse `$ARGUMENTS` to set runtime variables.
20
+
21
+ **Variables to set:**
22
+
23
+ - `PERSONA_FILTER` — array of lowercased persona names, or `"all"`. Default: `"all"`.
24
+ - `VERBOSE` — boolean. Default: `false`.
25
+ - `FORMAT` — `"markdown"` or `"json"`. Default: `"markdown"`.
26
+
27
+ **Parsing rules:**
28
+
29
+ 1. Scan `$ARGUMENTS` for `--persona <names>`. If found, split `<names>` on commas, lowercase each, set `PERSONA_FILTER=<array>`. Strip from arguments.
30
+ 2. Scan for `--verbose`. If found, set `VERBOSE=true`. Strip from arguments.
31
+ 3. Scan for `--format <value>`. If found and value is `json`, set `FORMAT="json"`. Any other value: print `Error: unknown format "<value>". Valid: markdown, json` and stop.
32
+
33
+ **Print active configuration:**
34
+
35
+ ```
36
+ Analyzing personas: <all | comma-separated list>
37
+ Format: <markdown|json>
38
+ Verbose: <yes|no>
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Phase 1: Load VPC Personas
44
+
45
+ Read the persona files to extract the VPC attribute definitions.
46
+
47
+ ### Step 1a: Discover persona files
48
+
49
+ Glob for persona files using these paths in order (use the first that yields results):
50
+
51
+ 1. `.claude/agents/` — look for `.md` files whose content includes a `## Value Proposition Canvas` section.
52
+ 2. `{{PERSONA_DIR}}/` — project-level persona directory (set by installer).
53
+
54
+ If no persona files are found in either location:
55
+
56
+ ```
57
+ Error: No VPC persona files found.
58
+ Expected location: .claude/agents/*.md or {{PERSONA_DIR}}/*.md
59
+ Each persona file must contain a ## Value Proposition Canvas section.
60
+ Run /setup to generate persona files from templates.
61
+ ```
62
+
63
+ Stop.
64
+
65
+ ### Step 1b: Parse each persona
66
+
67
+ For each discovered file, extract:
68
+
69
+ - `PERSONA_NAME` — from the `# Persona:` heading or frontmatter `name:` field.
70
+ - `PERSONA_ROLE` — from the profile table row `**Name**` (the role portion after "— The ").
71
+ - `JOBS` — rows from the `### Customer Jobs` table. Each row: `{ type, job }`.
72
+ - `PAINS` — rows from the `### Pains` table. Each row: `{ severity, pain }`.
73
+ - `GAINS` — rows from the `### Gains` table. Each row: `{ impact, gain }`.
74
+
75
+ If `PERSONA_FILTER` is not `"all"`, skip any persona whose lowercased name is not in `PERSONA_FILTER`.
76
+
77
+ Store parsed personas in `PERSONAS` (array of objects).
78
+
79
+ **Print after discovery:**
80
+
81
+ ```
82
+ Found <N> persona(s): <Name1> (<Role1>), <Name2> (<Role2>), ...
83
+ ```
84
+
85
+ If `PERSONA_FILTER` was applied and yielded 0 matches:
86
+
87
+ ```
88
+ Error: No personas matched filter: <PERSONA_FILTER>. Check spelling and try again.
89
+ ```
90
+
91
+ Stop.
92
+
93
+ ---
94
+
95
+ ## Phase 2: Load Product Signals
96
+
97
+ Gather the three signal sources: backlog, implemented features, and agent memory.
98
+
99
+ ### Step 2a: Backlog (requested features)
100
+
101
+ Load open/pending feature requests — these represent what the product *intends* to deliver.
102
+
103
+ 1. **Cache:** Check whether `.claude/backlog-cache.json` exists and is valid JSON. If so, read all issues from it (`issues` map). Set `BACKLOG_SOURCE="cache"`.
104
+ 2. **Live:** If no cache, run:
105
+ ```bash
106
+ {{BACKLOG_FETCH_ALL_CMD}}
107
+ ```
108
+ If the backlog provider is unavailable, set `BACKLOG_ITEMS=[]` and print:
109
+ ```
110
+ Warning: backlog provider unavailable. Backlog signal will be skipped.
111
+ ```
112
+ 3. Parse each backlog item to extract:
113
+ - `title` — feature name.
114
+ - `description` — feature description (first 300 chars).
115
+ - `persona_scores` — per-persona scores from the Overview table (if present). Format: `{ "Alex": 3, "Sara": 5, "Kai": 0 }`.
116
+ - `area` — from the `area:*` label.
117
+
118
+ Store in `BACKLOG_ITEMS`. Print: `Backlog loaded: <N> items (source: <cache|live>)`.
119
+
120
+ ### Step 2b: Implemented features
121
+
122
+ Gather signals about what has *actually been built*.
123
+
124
+ Run the following in sequence (each is best-effort — continue even if any fails):
125
+
126
+ **i. Git log (last 90 days):**
127
+ ```bash
128
+ git log --oneline --since="90 days ago" --no-merges 2>/dev/null
129
+ ```
130
+ Extract commit subjects. Filter out pure chore/docs/test/ci commits (those whose subject starts with `chore:`, `docs:`, `test:`, `ci:`). Store in `COMMIT_MESSAGES`.
131
+
132
+ **ii. CHANGELOG.md / CHANGELOG:**
133
+ Check whether `CHANGELOG.md` or `CHANGELOG` exists at the repo root. If found, read the last 500 lines. Extract headings and bullet points as feature descriptions. Store in `CHANGELOG_ENTRIES`.
134
+
135
+ **iii. Closed backlog issues (if GH available):**
136
+ ```bash
137
+ {{BACKLOG_FETCH_CLOSED_CMD}}
138
+ ```
139
+ Parse closed items the same way as open backlog items. Store in `CLOSED_ITEMS`.
140
+
141
+ Build `IMPLEMENTED_FEATURES` = array of strings combining `COMMIT_MESSAGES` + `CHANGELOG_ENTRIES` + closed item titles. Deduplicate by lowercased text.
142
+
143
+ Print: `Implemented signals: <N commits> commits, <N> changelog entries, <N> closed items`.
144
+
145
+ ### Step 2c: Agent memory usage patterns
146
+
147
+ Check whether `.claude/agent-memory/` exists. If it does, glob all `.md` files within it. For each file:
148
+ - Read the filename and first 200 chars of content.
149
+ - Extract any feature names, tool names, or workflow keywords mentioned.
150
+
151
+ Store extracted terms in `MEMORY_SIGNALS` (flat string array).
152
+
153
+ If the directory does not exist or is empty: set `MEMORY_SIGNALS=[]`. Print: `Agent memory: no signals found.`
154
+
155
+ Otherwise: Print: `Agent memory: <N> signals from <N> files.`
156
+
157
+ ---
158
+
159
+ ## Phase 3: Drift Analysis — Per Persona
160
+
161
+ For each persona in `PERSONAS`, perform a full alignment analysis.
162
+
163
+ ### Step 3a: Build a feature corpus
164
+
165
+ Create a combined text corpus:
166
+ ```
167
+ CORPUS = BACKLOG_ITEMS titles + descriptions
168
+ + IMPLEMENTED_FEATURES
169
+ + MEMORY_SIGNALS
170
+ ```
171
+
172
+ ### Step 3b: Attribute matching
173
+
174
+ For each VPC attribute (Job, Pain, Gain), determine whether it is *addressed* by the corpus.
175
+
176
+ **Matching rule:** An attribute is considered addressed if at least one corpus entry contains 2+ meaningful keyword matches from the attribute text. Use semantic matching (synonyms count — e.g., "slow" matches "latency", "performance"). If exact matching is insufficient, use AI-assisted reasoning to determine relevance.
177
+
178
+ For each attribute, record:
179
+ - `addressed` — boolean: is this attribute addressed?
180
+ - `matched_by` — array of corpus items (up to 3) that most strongly address it.
181
+ - `match_confidence` — `"strong"` (3+ keywords or explicit mention), `"weak"` (2 keywords, indirect), `"none"`.
182
+
183
+ ### Step 3c: Compute alignment scores
184
+
185
+ ```
186
+ JOBS_ADDRESSED = count(jobs where addressed=true)
187
+ PAINS_RELIEVED = count(pains where addressed=true)
188
+ GAINS_CREATED = count(gains where addressed=true)
189
+
190
+ JOBS_SCORE = JOBS_ADDRESSED / total_jobs (0.0–1.0)
191
+ PAINS_SCORE = PAINS_RELIEVED / total_pains (0.0–1.0)
192
+ GAINS_SCORE = GAINS_CREATED / total_gains (0.0–1.0)
193
+
194
+ OVERALL_SCORE = (JOBS_SCORE + PAINS_SCORE + GAINS_SCORE) / 3
195
+ ```
196
+
197
+ If a category has 0 attributes (e.g., no pains defined): exclude it from the OVERALL_SCORE denominator.
198
+
199
+ ### Step 3d: Classify drift level
200
+
201
+ | Overall Score | Drift Level |
202
+ |---------------|-------------|
203
+ | ≥ 0.80 | Low |
204
+ | 0.60–0.79 | Medium |
205
+ | 0.40–0.59 | High |
206
+ | < 0.40 | Critical |
207
+
208
+ ### Step 3e: Identify drifted attributes
209
+
210
+ A VPC attribute is **drifted** when `addressed=false`.
211
+
212
+ Rank drifted attributes by severity/impact weight:
213
+ - Pains with severity `critical` → weight 3
214
+ - Pains with severity `high` or Jobs/Gains with impact `high` → weight 2
215
+ - All others → weight 1
216
+
217
+ Sort drifted attributes by weight descending.
218
+
219
+ ### Step 3f: Identify misaligned backlog items
220
+
221
+ A backlog item is **misaligned** for this persona when:
222
+ 1. The item's `persona_scores` gives this persona a score of 0, AND
223
+ 2. The item's description does not match any of this persona's VPC attributes (by the same matching rule as Step 3b).
224
+
225
+ OR when the item has no persona score data at all and its description does not semantically relate to any of this persona's Jobs/Pains/Gains.
226
+
227
+ ### Step 3g: Generate VPC update recommendations
228
+
229
+ For each drifted attribute (weight ≥ 2), produce a concrete recommendation:
230
+
231
+ - If many features address a *different* pain than what's defined: "Consider updating the `<Pain>` attribute to reflect the observed pattern: [observed pattern]."
232
+ - If a Job is completely unaddressed across the product: "Either prioritize features addressing `<Job>`, or remove it from the VPC if no longer relevant."
233
+ - If a Gain is partially addressed: "Strengthen the `<Gain>` attribute description to capture the nuance being delivered by [feature(s)]."
234
+
235
+ Limit to top 5 recommendations per persona, sorted by weight descending.
236
+
237
+ Store per-persona results in `PERSONA_DRIFT` array.
238
+
239
+ ---
240
+
241
+ ## Phase 4: Detect Cross-Persona Patterns
242
+
243
+ After all per-persona analyses are complete, look for systemic patterns.
244
+
245
+ **Over-represented persona:** If one persona's backlog items make up > 60% of total items, flag it:
246
+ ```
247
+ ⚠️ Over-representation detected: <PersonaName> drives <N>% of backlog items.
248
+ This may indicate under-investment in other personas' pain points.
249
+ ```
250
+
251
+ **Under-served persona:** If a persona's OVERALL_SCORE < 0.40:
252
+ ```
253
+ 🚨 Critical drift for <PersonaName>: only <N>% of their VPC attributes are being addressed.
254
+ ```
255
+
256
+ **Orphan backlog items:** Items with no persona scores at all (neither from score data nor semantic matching). Count them. If > 20% of total backlog, flag:
257
+ ```
258
+ ⚠️ <N> backlog items (<N>%) have no clear persona linkage.
259
+ Consider running /sr:update-product-driven-backlog to re-evaluate them.
260
+ ```
261
+
262
+ Store in `CROSS_PERSONA_FINDINGS`.
263
+
264
+ ---
265
+
266
+ ## Phase 5: Build and Render Drift Report
267
+
268
+ ### If FORMAT = "json"
269
+
270
+ Emit a single JSON object:
271
+
272
+ ```json
273
+ {
274
+ "schema_version": "1",
275
+ "project": "{{PROJECT_NAME}}",
276
+ "generated_at": "<ISO 8601 timestamp>",
277
+ "personas": [
278
+ {
279
+ "name": "<PersonaName>",
280
+ "role": "<Role>",
281
+ "drift_level": "<Low|Medium|High|Critical>",
282
+ "scores": {
283
+ "jobs": <0.0–1.0>,
284
+ "pains": <0.0–1.0>,
285
+ "gains": <0.0–1.0>,
286
+ "overall": <0.0–1.0>
287
+ },
288
+ "drifted_attributes": [
289
+ { "category": "<job|pain|gain>", "text": "...", "weight": <1|2|3> }
290
+ ],
291
+ "misaligned_items": ["<title>", ...],
292
+ "recommendations": ["..."]
293
+ }
294
+ ],
295
+ "cross_persona_findings": ["..."],
296
+ "summary": {
297
+ "total_personas": <N>,
298
+ "critical": <N>,
299
+ "high": <N>,
300
+ "medium": <N>,
301
+ "low": <N>
302
+ }
303
+ }
304
+ ```
305
+
306
+ Stop after emitting JSON.
307
+
308
+ ### If FORMAT = "markdown"
309
+
310
+ Render the full drift report:
311
+
312
+ ```
313
+ ## VPC Persona Drift Report — {{PROJECT_NAME}}
314
+ Generated: <YYYY-MM-DD HH:MM> | Backlog: <N> items | Implemented signals: <N>
315
+
316
+ ### Summary
317
+
318
+ | Persona | Role | Jobs | Pains | Gains | Overall | Drift Level |
319
+ |---------|------|------|-------|-------|---------|-------------|
320
+ | <Name> | <Role> | <N%> | <N%> | <N%> | <N%> | 🟢 Low / 🟡 Medium / 🟠 High / 🔴 Critical |
321
+
322
+ <for each CROSS_PERSONA_FINDING: render the warning/flag block>
323
+
324
+ ---
325
+ ```
326
+
327
+ Then for each persona:
328
+
329
+ ```
330
+ ### Persona: <Name> — <Role>
331
+
332
+ **Drift Level:** 🟢/🟡/🟠/🔴 <Level> | **Alignment: <N>%** (Jobs: <N>%, Pains: <N>%, Gains: <N>%)
333
+
334
+ #### ✅ Addressed Attributes (<N> of <total>)
335
+
336
+ <if VERBOSE=true:>
337
+ | Category | Attribute | Confidence | Matched by |
338
+ |----------|-----------|------------|------------|
339
+ | Job | <text> | Strong | <feature1>, <feature2> |
340
+ | Pain | <text> | Weak | <feature1> |
341
+
342
+ <if VERBOSE=false:>
343
+ - **Jobs**: <N> of <total> addressed
344
+ - **Pains**: <N> of <total> relieved
345
+ - **Gains**: <N> of <total> created
346
+
347
+ #### ⚠️ Drifted Attributes (<N> unaddressed)
348
+
349
+ | Category | Attribute | Severity/Impact | Weight |
350
+ |----------|-----------|-----------------|--------|
351
+ | Pain | <text> | critical | ●●● |
352
+ | Job | <text> | high | ●● |
353
+ | Gain | <text> | medium | ● |
354
+
355
+ <if no drifted attributes:>
356
+ _No drifted attributes — all VPC definitions are reflected in the product._
357
+
358
+ #### ❌ Misaligned Backlog Items (<N> items)
359
+
360
+ <if items exist:>
361
+ | # | Title | Persona Score | Why Misaligned |
362
+ |---|-------|---------------|----------------|
363
+ | <number> | <title> | 0/5 | No matching VPC attribute |
364
+
365
+ <if no items:>
366
+ _All backlog items have clear VPC alignment for this persona._
367
+
368
+ #### 💡 Recommended VPC Updates
369
+
370
+ <numbered list of up to 5 recommendations>
371
+
372
+ ---
373
+ ```
374
+
375
+ After all personas:
376
+
377
+ ```
378
+ ### Next Steps
379
+
380
+ 1. Review drifted attributes and decide: **update VPC** (if the product has legitimately evolved) or **add backlog items** (if the persona's needs are being neglected).
381
+ 2. Run `/sr:update-product-driven-backlog` after updating personas to regenerate aligned feature ideas.
382
+ 3. Re-run `/sr:vpc-drift` after one sprint to measure improvement.
383
+
384
+ _Generated by `/sr:vpc-drift` in {{PROJECT_NAME}} on <ISO date>_
385
+ ```
386
+
387
+ ---
388
+
389
+ ## Phase 6: Save Snapshot (optional)
390
+
391
+ After rendering, write a drift snapshot to `.claude/health-history/`:
392
+
393
+ 1. Filename: `vpc-drift-<YYYY-MM-DD>.json`
394
+ 2. Directory: `.claude/vpc-drift-history/` (create if absent, idempotent).
395
+ 3. Content: the same JSON object described in Phase 5 (regardless of FORMAT setting).
396
+
397
+ Print: `Snapshot saved: .claude/vpc-drift-history/vpc-drift-<YYYY-MM-DD>.json`
398
+
399
+ If the write fails: print `Warning: could not write drift snapshot. Continuing.` Do not abort.
400
+
401
+ **Housekeeping:** If `.claude/vpc-drift-history/` has more than 30 `.json` files, print:
402
+ ```
403
+ Note: .claude/vpc-drift-history/ has <N> snapshots. Prune old ones with:
404
+ ls -t .claude/vpc-drift-history/ | tail -n +31 | xargs -I{} rm .claude/vpc-drift-history/{}
405
+ ```
@@ -35,6 +35,8 @@
35
35
  | Functional | Maintain coding standards across a growing contributor base |
36
36
  | Functional | Triage issues and PRs — separate signal from noise |
37
37
  | Functional | Keep CI/CD green and catch regressions early |
38
+ | Functional | Keep dependencies up to date without introducing breaking changes |
39
+ | Functional | Coordinate releases — changelog curation, versioning, and publishing |
38
40
  | Social | Build a healthy community where contributors feel welcomed and guided |
39
41
  | Emotional | Avoid burnout from the growing volume of contributions and issues |
40
42
  | Emotional | Feel that their project is sustainable, not just surviving |
@@ -49,6 +51,8 @@
49
51
  | High | No way to enforce project-specific coding standards automatically beyond basic linting |
50
52
  | Medium | Automated scanning tools (security, code quality) generate noise — hard to distinguish real issues |
51
53
  | Medium | Onboarding contributors to the project's specific patterns and conventions is time-consuming |
54
+ | Medium | Dependency upgrades require manual changelog review and breakage risk assessment — Dependabot creates noise without project-specific context |
55
+ | Medium | Release coordination is manual — changelog curation, version bumping, and publishing require synchronous maintainer attention |
52
56
  | Medium | Feature requests pile up with no framework to evaluate which ones matter most to users |
53
57
  | Low | Sponsorship/funding doesn't scale with project popularity or maintenance burden |
54
58
 
@@ -69,6 +73,22 @@
69
73
 
70
74
  > Open-source maintainers are the most **time-constrained** users in the software ecosystem. They don't need more AI to *write* code — they need AI that *understands their project deeply enough* to review contributions, enforce conventions, and handle routine tasks so they can focus on architecture and community. The key unlock is project-specific intelligence, not generic coding ability.
71
75
 
76
+ ## Feature Evaluation Criteria
77
+
78
+ When evaluating whether a feature is worth Kai's time and adoption risk:
79
+
80
+ | Criterion | Question |
81
+ |-----------|----------|
82
+ | **Review burden** | Does this reduce time spent reviewing contributions without adding maintainer overhead? |
83
+ | **Convention enforcement** | Does this enforce project-specific rules, not just generic coding standards? |
84
+ | **GitHub-native** | Does this work with Issues, PRs, and Actions — the tools Kai already lives in? |
85
+ | **Cost ceiling** | Is this free or under $20/month? (OSS projects cannot justify SaaS pricing) |
86
+ | **Contributor UX** | Does this improve contributor experience without adding new maintainer responsibilities? |
87
+ | **Backwards compatibility** | Does this respect the project's stability contract with existing users? |
88
+ | **Scale range** | Does this work for a 200-star hobby project and a 50k-star ecosystem library alike? |
89
+
90
+ A feature scores high for Kai (4-5/5) when it reduces async review work, enforces conventions automatically, or handles routine coordination (dependency updates, release notes) without requiring Kai to be online. A feature scores low (0-1/5) when it adds configuration burden, requires paid tiers, or is primarily useful for teams rather than solo/small maintainer groups.
91
+
72
92
  ## Sources
73
93
 
74
94
  - [GitHub Blog — Welcome to the Eternal September of Open Source](https://github.blog/open-source/maintainers/welcome-to-the-eternal-september-of-open-source-heres-what-we-plan-to-do-for-maintainers/)