@tcanaud/product-manager 1.0.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,188 @@
1
+ ---
2
+ description: View product health dashboard — status counts, category distribution, conversion metrics, and warnings.
3
+ handoffs:
4
+ - label: Triage feedbacks
5
+ agent: product.triage
6
+ prompt: Triage new feedbacks into backlogs
7
+ send: true
8
+ - label: Check health
9
+ agent: product.check
10
+ prompt: Run product health check
11
+ send: true
12
+ - label: Browse backlogs
13
+ agent: product.backlog
14
+ prompt: List all backlogs
15
+ send: true
16
+ ---
17
+
18
+ ## User Input
19
+
20
+ ```text
21
+ $ARGUMENTS
22
+ ```
23
+
24
+ You **MUST** consider the user input before proceeding (if not empty).
25
+
26
+ - If `$ARGUMENTS` contains `--json`: output structured JSON instead of Markdown
27
+ - Otherwise: output Markdown dashboard
28
+
29
+ ## Purpose
30
+
31
+ Read-only command that displays a complete product health overview: feedback counts by status, backlog counts by status, category distribution, conversion metrics (feedback-to-backlog rate, backlog-to-feature rate, resolution rate), and warnings for stale feedbacks or critical bugs.
32
+
33
+ ## Execution Flow
34
+
35
+ ### 1. Validate environment
36
+
37
+ - Check that `.product/` directory exists. If not → **ERROR**: "Product directory not initialized."
38
+
39
+ ### 2. Gather data
40
+
41
+ Scan the filesystem directly for accurate counts:
42
+
43
+ **Feedbacks:**
44
+ - Count files in `.product/feedbacks/new/`
45
+ - Count files in `.product/feedbacks/triaged/`
46
+ - Count files in `.product/feedbacks/excluded/`
47
+ - Count files in `.product/feedbacks/resolved/`
48
+
49
+ **Backlogs:**
50
+ - Count files in `.product/backlogs/open/`
51
+ - Count files in `.product/backlogs/in-progress/`
52
+ - Count files in `.product/backlogs/done/`
53
+ - Count files in `.product/backlogs/promoted/`
54
+ - Count files in `.product/backlogs/cancelled/`
55
+
56
+ **Categories:**
57
+ - For each feedback file across all status directories, read the `category` field from frontmatter
58
+ - Count occurrences of each category: `critical-bug`, `bug`, `optimization`, `evolution`, `new-feature`
59
+
60
+ **Backlog priorities:**
61
+ - For each backlog file across all status directories, read the `priority` field
62
+
63
+ ### 3. Compute metrics
64
+
65
+ - **Feedback-to-backlog rate**: count of feedbacks with non-empty `linked_to.backlog[]` / total non-excluded feedbacks. If total non-excluded is 0, rate = 0.
66
+ - **Backlog-to-feature rate**: count of promoted backlogs / total backlogs. If total backlogs is 0, rate = 0.
67
+ - **Resolution rate**: count of resolved feedbacks / total feedbacks. If total feedbacks is 0, rate = 0.
68
+
69
+ ### 4. Identify warnings
70
+
71
+ - **Stale feedbacks**: For each feedback in `feedbacks/new/`, read the `created` date. If today minus created > 14 days → add stale warning with count and oldest age.
72
+ - **Critical bugs**: For each backlog with `priority: critical` → add critical bug alert with ID and title.
73
+
74
+ ### 5. Output — Markdown (default)
75
+
76
+ ```markdown
77
+ ## Product Dashboard
78
+
79
+ **Last updated**: {today's date}
80
+
81
+ ### Feedbacks
82
+
83
+ | Status | Count |
84
+ |--------|-------|
85
+ | New | {count} |
86
+ | Triaged | {count} |
87
+ | Excluded | {count} |
88
+ | Resolved | {count} |
89
+ | **Total** | **{total}** |
90
+
91
+ ### Backlogs
92
+
93
+ | Status | Count |
94
+ |--------|-------|
95
+ | Open | {count} |
96
+ | In Progress | {count} |
97
+ | Done | {count} |
98
+ | Promoted | {count} |
99
+ | Cancelled | {count} |
100
+ | **Total** | **{total}** |
101
+
102
+ ### Categories
103
+
104
+ | Category | Count | % |
105
+ |----------|-------|---|
106
+ | critical-bug | {count} | {pct}% |
107
+ | bug | {count} | {pct}% |
108
+ | optimization | {count} | {pct}% |
109
+ | evolution | {count} | {pct}% |
110
+ | new-feature | {count} | {pct}% |
111
+
112
+ ### Conversion Metrics
113
+
114
+ | Metric | Value |
115
+ |--------|-------|
116
+ | Feedback → Backlog | {rate}% |
117
+ | Backlog → Feature | {rate}% |
118
+ | Resolution rate | {rate}% |
119
+
120
+ ### Warnings
121
+
122
+ {If stale feedbacks:}
123
+ - **{count} stale feedback(s)** in `new/` (oldest: {days} days) — run `/product.triage`
124
+
125
+ {If critical bugs:}
126
+ - **{count} critical bug(s)** in backlogs — {id} "{title}"
127
+
128
+ {If no warnings:}
129
+ No warnings.
130
+ ```
131
+
132
+ If the product directory is empty (no feedbacks, no backlogs), display the dashboard with all zeros and add:
133
+ > No feedbacks or backlogs yet. Start with `/product.intake`.
134
+
135
+ ### 6. Output — JSON (`--json` flag)
136
+
137
+ Output a structured JSON object:
138
+
139
+ ```json
140
+ {
141
+ "updated": "{ISO timestamp}",
142
+ "feedbacks": {
143
+ "total": {n},
144
+ "new": {n},
145
+ "triaged": {n},
146
+ "excluded": {n},
147
+ "resolved": {n}
148
+ },
149
+ "backlogs": {
150
+ "total": {n},
151
+ "open": {n},
152
+ "in_progress": {n},
153
+ "done": {n},
154
+ "promoted": {n},
155
+ "cancelled": {n}
156
+ },
157
+ "categories": {
158
+ "critical-bug": {n},
159
+ "bug": {n},
160
+ "optimization": {n},
161
+ "evolution": {n},
162
+ "new-feature": {n}
163
+ },
164
+ "metrics": {
165
+ "feedback_to_backlog_rate": {float},
166
+ "backlog_to_feature_rate": {float},
167
+ "resolution_rate": {float}
168
+ },
169
+ "warnings": [
170
+ { "type": "stale_feedbacks", "count": {n}, "oldest_days": {n} },
171
+ { "type": "critical_bug", "id": "{BL-xxx}", "title": "{title}" }
172
+ ]
173
+ }
174
+ ```
175
+
176
+ ## Error Handling
177
+
178
+ - `.product/` missing → ERROR with init instructions
179
+ - Empty `.product/` → display dashboard with all zeros and a note
180
+
181
+ ## Rules
182
+
183
+ - This command is **READ-ONLY** — no files are modified
184
+ - ALWAYS scan the filesystem directly for accurate counts — do not rely solely on index.yaml
185
+ - ALWAYS compute percentages as integers (rounded)
186
+ - ALWAYS show all categories even if count is 0
187
+ - ALWAYS show all status groups even if count is 0
188
+ - NEVER modify any files
@@ -0,0 +1,125 @@
1
+ ---
2
+ description: Capture feedback from free text or inbox files into structured .product/feedbacks/new/ entries.
3
+ handoffs:
4
+ - label: Triage feedbacks
5
+ agent: product.triage
6
+ prompt: Triage new feedbacks into backlogs
7
+ send: true
8
+ - label: View dashboard
9
+ agent: product.dashboard
10
+ prompt: View product health dashboard
11
+ send: true
12
+ ---
13
+
14
+ ## User Input
15
+
16
+ ```text
17
+ $ARGUMENTS
18
+ ```
19
+
20
+ You **MUST** consider the user input before proceeding (if not empty).
21
+
22
+ ## Purpose
23
+
24
+ Capture user feedback — either from free-text arguments or from files dropped in `.product/inbox/` — and create structured feedback entries in `.product/feedbacks/new/` with proper YAML frontmatter. This is the entry point for all product feedback.
25
+
26
+ ## Execution Flow
27
+
28
+ ### 1. Validate environment
29
+
30
+ - Check that `.product/` directory exists. If not → **ERROR**: "Product directory not initialized. Run `npx @tcanaud/product-manager init` first."
31
+ - Check that `.product/_templates/feedback.tpl.md` exists. If not → **ERROR**: "Feedback template missing. Run `npx @tcanaud/product-manager update` to restore templates."
32
+
33
+ ### 2. Determine intake mode
34
+
35
+ - **If `$ARGUMENTS` is non-empty**: Free-text mode (Mode 1) is active
36
+ - **Check `.product/inbox/`**: If inbox has files, inbox mode (Mode 2) is active
37
+ - **If both**: Combined mode — process both
38
+ - **If neither**: **INFO**: "No feedback to process. Provide a description or drop files in `.product/inbox/`." → STOP
39
+
40
+ ### 3. Assign next ID
41
+
42
+ Scan ALL `.product/feedbacks/` subdirectories (`new/`, `triaged/`, `excluded/`, `resolved/`) for existing feedback files. Extract the numeric portion from filenames matching `FB-xxx.md`. Find the highest number and increment by 1. Zero-pad to 3 digits.
43
+
44
+ Example: If highest existing is `FB-012.md` → next ID is `FB-013`.
45
+ If no feedbacks exist → start at `FB-001`.
46
+
47
+ ### 4. Mode 1 — Free-text intake (if `$ARGUMENTS` provided)
48
+
49
+ 1. Read `.product/_templates/feedback.tpl.md` for the schema
50
+ 2. Analyze the free-text content to:
51
+ - Extract a concise **title** (max 80 chars) summarizing the feedback
52
+ - Propose a **category** from: `critical-bug`, `bug`, `optimization`, `evolution`, `new-feature`
53
+ - Determine **source**: default to `user`
54
+ 3. Create the feedback file at `.product/feedbacks/new/FB-{NNN}.md`:
55
+ - Replace `{{id}}` with `FB-{NNN}`
56
+ - Replace `{{title}}` with the extracted title
57
+ - Replace `{{category}}` with the proposed category
58
+ - Replace `{{source}}` with `user`
59
+ - Replace `{{reporter}}` with the git user name (from `git config user.name`) or `unknown`
60
+ - Replace `{{created}}` and `{{updated}}` with today's date (YYYY-MM-DD)
61
+ - Replace `{{body}}` with the full free-text description
62
+ 4. Record this feedback for the summary report
63
+
64
+ ### 5. Mode 2 — Inbox processing (if `.product/inbox/` has files)
65
+
66
+ 1. List all files in `.product/inbox/`
67
+ 2. For each file:
68
+ a. Read the file content
69
+ b. If the file appears to be binary or empty → **WARN**: "Skipped {filename}: unrecognizable content. Left in inbox for manual review." → skip
70
+ c. Check for YAML frontmatter (between `---` markers):
71
+ - If present: extract `source`, `reporter`, `timestamp` fields
72
+ - If absent: infer metadata from content
73
+ d. Assign next sequential ID (continuing from Mode 1 if both modes active)
74
+ e. Analyze content to propose category and extract title
75
+ f. Create structured feedback in `.product/feedbacks/new/FB-{NNN}.md`:
76
+ - Use extracted/inferred metadata for frontmatter fields
77
+ - Use the file content (minus frontmatter) as the body
78
+ g. Delete the processed inbox file
79
+ 3. Record each created feedback for the summary report
80
+
81
+ ### 6. Update index
82
+
83
+ Read `.product/index.yaml`. For each new feedback created:
84
+ - Increment `feedbacks.total` by 1
85
+ - Increment `feedbacks.by_status.new` by 1
86
+ - Increment the appropriate `feedbacks.by_category.{category}` by 1
87
+ - Add an entry to `feedbacks.items[]` with: id, title, status, category, priority, created
88
+ - Update the `updated` timestamp
89
+
90
+ Write the updated index back to `.product/index.yaml`.
91
+
92
+ ### 7. Output report
93
+
94
+ Display a Markdown summary:
95
+
96
+ ```markdown
97
+ ## Intake Complete
98
+
99
+ **Created**: {count} new feedback(s)
100
+
101
+ | ID | Title | Category | Source |
102
+ |----|-------|----------|--------|
103
+ | FB-{NNN} | {title} | {category} | {source} |
104
+ | ... | ... | ... | ... |
105
+
106
+ **Next**: Run `/product.triage` when ready to process new feedbacks.
107
+ ```
108
+
109
+ ## Error Handling
110
+
111
+ - `.product/` does not exist → ERROR with initialization instructions
112
+ - No arguments AND empty inbox → INFO message, no action taken
113
+ - Inbox file is empty or binary → WARN, skip that file, continue with others
114
+ - Unreadable inbox file → WARN, leave file in inbox for manual review
115
+
116
+ ## Rules
117
+
118
+ - ALWAYS assign IDs by scanning ALL feedbacks/ subdirectories — never reuse IDs
119
+ - ALWAYS use today's date for `created` and `updated`
120
+ - ALWAYS set `status: "new"` for newly created feedbacks
121
+ - ALWAYS update `index.yaml` after creating feedbacks
122
+ - ALWAYS delete successfully processed inbox files
123
+ - NEVER modify existing feedback files
124
+ - NEVER modify backlog files
125
+ - Category MUST be one of: `critical-bug`, `bug`, `optimization`, `evolution`, `new-feature`
@@ -0,0 +1,159 @@
1
+ ---
2
+ description: Promote a backlog item to a full kai feature with traceability links.
3
+ handoffs:
4
+ - label: Start feature workflow
5
+ agent: feature.workflow
6
+ prompt: Start the feature workflow for the newly created feature
7
+ send: true
8
+ - label: Browse backlogs
9
+ agent: product.backlog
10
+ prompt: List all backlogs
11
+ send: true
12
+ - label: View dashboard
13
+ agent: product.dashboard
14
+ prompt: View product health dashboard
15
+ send: true
16
+ ---
17
+
18
+ ## User Input
19
+
20
+ ```text
21
+ $ARGUMENTS
22
+ ```
23
+
24
+ You **MUST** consider the user input before proceeding (if not empty).
25
+
26
+ `$ARGUMENTS` must contain a backlog ID (e.g., `BL-001`).
27
+
28
+ ## Purpose
29
+
30
+ Convert a backlog item into a kai feature — creating the `.features/{NNN}-{name}.yaml` file, updating `.features/index.yaml`, moving the backlog to `promoted/`, and updating all traceability links through the feedback → backlog → feature chain.
31
+
32
+ ## Execution Flow
33
+
34
+ ### 1. Validate arguments
35
+
36
+ - If `$ARGUMENTS` is empty → **ERROR**: "Backlog ID required. Usage: `/product.promote BL-xxx`"
37
+ - Extract the backlog ID from arguments (should match pattern `BL-\d{3}`)
38
+ - If invalid format → **ERROR**: "Invalid backlog ID format. Expected BL-xxx (e.g., BL-001)."
39
+
40
+ ### 2. Find the backlog
41
+
42
+ Search for the backlog file across these directories (in order):
43
+ 1. `.product/backlogs/open/`
44
+ 2. `.product/backlogs/in-progress/`
45
+
46
+ If found in `promoted/` → **ERROR**: "Backlog {id} is already promoted (feature: {feature_id})."
47
+ If found in `done/` or `cancelled/` → **ERROR**: "Cannot promote a {status} backlog. Only open or in-progress backlogs can be promoted."
48
+ If not found anywhere → **ERROR**: "Backlog {id} not found."
49
+
50
+ Read the backlog file: parse YAML frontmatter and body content.
51
+
52
+ ### 3. Determine feature identity
53
+
54
+ 1. Read `.features/index.yaml` to list all existing features
55
+ 2. Scan `.features/` for all `{NNN}-*.yaml` files
56
+ 3. Find the highest feature number (NNN)
57
+ 4. Next feature number = highest + 1, zero-padded to 3 digits
58
+ 5. Derive the feature name from the backlog title:
59
+ - Convert to lowercase
60
+ - Replace spaces and special characters with hyphens
61
+ - Remove consecutive hyphens
62
+ - Trim hyphens from start/end
63
+ - Example: "Search Performance on Large Repos" → `search-performance-on-large-repos`
64
+ 6. Feature ID = `{NNN}-{name}` (e.g., `009-search-performance-on-large-repos`)
65
+
66
+ ### 4. Create feature YAML
67
+
68
+ 1. Read `.features/_templates/feature.tpl.yaml`
69
+ 2. Copy to `.features/{feature_id}.yaml`
70
+ 3. Replace template placeholders:
71
+ - `{{feature_id}}` → the feature ID
72
+ - `{{title}}` → the backlog title (title case)
73
+ - `{{owner}}` → the backlog `owner` field, or `default_owner` from `.features/config.yaml`
74
+ - `{{date}}` → today's date (YYYY-MM-DD)
75
+ - `{{timestamp}}` → current ISO timestamp
76
+ 4. Set `workflow_path: "full"` (promoted features use the full method)
77
+
78
+ ### 5. Update feature index
79
+
80
+ Read `.features/index.yaml` and add the new feature entry:
81
+ - `id`: the feature ID
82
+ - `title`: the backlog title
83
+ - `status`: `active`
84
+ - `stage`: `ideation`
85
+ - `progress`: `0.0`
86
+ - `health`: `HEALTHY`
87
+
88
+ Write the updated index back.
89
+
90
+ ### 6. Update backlog
91
+
92
+ 1. Move the backlog file from its current directory to `.product/backlogs/promoted/`
93
+ 2. Update the backlog frontmatter:
94
+ - `status: "promoted"`
95
+ - `updated: today's date`
96
+ - `promotion.promoted_date: today's date`
97
+ - `promotion.feature_id: "{feature_id}"`
98
+ - Add the feature ID to `features[]` array
99
+ 3. Write the updated file
100
+
101
+ ### 7. Update linked feedbacks
102
+
103
+ For each feedback ID in the backlog's `feedbacks[]` array:
104
+ 1. Find the feedback file across all `feedbacks/` subdirectories
105
+ 2. Read its frontmatter
106
+ 3. Add the feature ID to `linked_to.features[]`
107
+ 4. Update `updated` to today's date
108
+ 5. Write the updated file
109
+
110
+ ### 8. Update product index
111
+
112
+ Read `.product/index.yaml` and update:
113
+ - Decrement the appropriate `backlogs.by_status.{old_status}` count
114
+ - Increment `backlogs.by_status.promoted`
115
+ - Update the backlog entry in `backlogs.items[]`
116
+ - Recalculate `metrics.backlog_to_feature_rate`
117
+ - Update `updated` timestamp
118
+
119
+ Write the updated index back.
120
+
121
+ ### 9. Output report
122
+
123
+ ```markdown
124
+ ## Promotion Complete
125
+
126
+ **Backlog**: {backlog_id} → promoted
127
+ **Feature**: {feature_id} created
128
+
129
+ ### Traceability Chain
130
+
131
+ {For each linked feedback:}
132
+ FB-xxx ──→ {backlog_id} ──→ {feature_id}
133
+
134
+ ### Next Steps
135
+
136
+ 1. Run `/feature.workflow {feature_id}` to start the feature pipeline
137
+ 2. The feature begins at **ideation** stage — proceed through Brief → PRD → Spec → Tasks → Code
138
+ ```
139
+
140
+ ## Error Handling
141
+
142
+ - `$ARGUMENTS` is empty → ERROR with usage instructions
143
+ - Backlog not found → ERROR with ID
144
+ - Backlog already promoted → ERROR with existing feature ID
145
+ - Backlog in wrong status (done/cancelled) → ERROR with explanation
146
+ - `.features/` missing → ERROR: "Feature lifecycle system not initialized. Run `npx feature-lifecycle init` first."
147
+ - `.features/_templates/feature.tpl.yaml` missing → ERROR: "Feature template missing."
148
+ - Feature index update fails → ERROR but backlog move is already done — instruct to run `/product.check`
149
+
150
+ ## Rules
151
+
152
+ - ALWAYS validate the backlog exists and is in a promotable status before any mutations
153
+ - ALWAYS create the feature YAML before moving the backlog (fail-safe ordering)
154
+ - ALWAYS update bidirectional links: backlog → feature AND feedback → feature
155
+ - ALWAYS use the next sequential feature number from `.features/`
156
+ - NEVER modify feedbacks beyond adding to `linked_to.features[]` and updating `updated`
157
+ - NEVER promote backlogs in `done/` or `cancelled/` status
158
+ - NEVER overwrite an existing feature YAML
159
+ - Feature name derivation MUST produce valid kebab-case (lowercase, hyphens only)
@@ -0,0 +1,205 @@
1
+ ---
2
+ description: Triage new feedbacks — semantic clustering, duplicate/regression detection, backlog creation.
3
+ handoffs:
4
+ - label: Browse backlogs
5
+ agent: product.backlog
6
+ prompt: List all backlogs
7
+ send: true
8
+ - label: Promote backlog
9
+ agent: product.promote
10
+ prompt: Promote a backlog to feature
11
+ send: true
12
+ - label: View dashboard
13
+ agent: product.dashboard
14
+ prompt: View product health dashboard
15
+ send: true
16
+ ---
17
+
18
+ ## User Input
19
+
20
+ ```text
21
+ $ARGUMENTS
22
+ ```
23
+
24
+ You **MUST** consider the user input before proceeding (if not empty).
25
+
26
+ - If `$ARGUMENTS` contains `--supervised`: use supervised mode (confirm each action)
27
+ - Otherwise: use autonomous mode (execute all actions immediately)
28
+
29
+ ## Purpose
30
+
31
+ Read all new feedbacks, perform AI semantic clustering, detect duplicates and regressions against resolved feedbacks, propose backlog items, and execute triage actions — moving feedbacks to `triaged/` or `excluded/` and creating backlog items in `backlogs/open/`.
32
+
33
+ ## Execution Flow
34
+
35
+ ### 1. Validate environment
36
+
37
+ - Check that `.product/` directory exists. If not → **ERROR**: "Product directory not initialized."
38
+ - List files in `.product/feedbacks/new/`. If empty → **INFO**: "No new feedbacks to triage." → STOP
39
+ - If more than 30 feedbacks in `new/` → **WARN**: "Large batch ({count} feedbacks). Processing first 30; re-run for remainder." Process only the first 30 (sorted by filename).
40
+
41
+ ### 2. Read all feedbacks for context
42
+
43
+ Read **all** feedback files from:
44
+ - `.product/feedbacks/new/` — the feedbacks to triage (primary input)
45
+ - `.product/feedbacks/resolved/` — for regression/duplicate detection
46
+ - `.product/feedbacks/triaged/` — for existing context and deduplication
47
+
48
+ For each file, parse the YAML frontmatter and body content.
49
+
50
+ ### 3. Read existing backlogs for context
51
+
52
+ Read all backlog files from all `.product/backlogs/` subdirectories to understand what already exists and avoid creating duplicate backlogs.
53
+
54
+ ### 4. Semantic analysis
55
+
56
+ For each new feedback, perform the following analysis:
57
+
58
+ #### 4a. Clustering
59
+
60
+ Group new feedbacks that describe the **same problem or request**, even with different phrasings. Use semantic understanding — NOT keyword matching.
61
+
62
+ Example: "Search takes 40 seconds" and "Search is unusable with 10k files" → same cluster (search performance).
63
+
64
+ #### 4b. Regression / duplicate detection
65
+
66
+ Compare each new feedback against **resolved** feedbacks:
67
+
68
+ 1. If semantically similar to a resolved feedback:
69
+ - Find the resolution chain: read the resolved feedback's `linked_to.backlog[]` → read that backlog's `features[]` → find the feature
70
+ - Read the feature's `.features/{feature_id}.yaml` to get `lifecycle.stage` and `lifecycle.stage_since`
71
+ - **If** feedback `created` date > feature `stage_since` date (feature was released BEFORE the new feedback was created) → classify as **REGRESSION**
72
+ - **If** feedback `created` date <= feature `stage_since` date → classify as **DUPLICATE-RESOLVED**
73
+ 2. If no resolution chain can be traced, treat as a new standalone feedback
74
+
75
+ #### 4c. Category assignment
76
+
77
+ For each feedback, verify or reassign its category from the predefined set: `critical-bug`, `bug`, `optimization`, `evolution`, `new-feature`.
78
+
79
+ #### 4d. Priority proposal
80
+
81
+ For each cluster/standalone feedback, propose a priority: `low`, `medium`, `high`, `critical`.
82
+ Consider: user impact, frequency of reports, severity of the issue.
83
+
84
+ ### 5. Present triage proposal
85
+
86
+ Build a structured proposal showing all planned actions:
87
+
88
+ ```markdown
89
+ ## Triage Proposal
90
+
91
+ ### Group 1: {cluster title} ({count} feedbacks)
92
+ - FB-xxx: "{title}"
93
+ - FB-yyy: "{title}"
94
+ **Action**: Create backlog BL-{NNN} "{proposed title}" ({category}, {priority})
95
+
96
+ ### Group 2: Standalone
97
+ - FB-zzz: "{title}"
98
+ **Action**: Create backlog BL-{NNN} "{proposed title}" ({category}, {priority})
99
+
100
+ ### Excluded
101
+ - FB-aaa: "{title}"
102
+ **Action**: Move to excluded/ (reason: {noise | out-of-scope | duplicate-resolved | ...})
103
+
104
+ ### Regression Detected
105
+ - FB-bbb: Similar to resolved FB-ccc (resolved by feature {feature_id}, released {date})
106
+ FB-bbb created: {date} — AFTER release
107
+ **Action**: Create backlog BL-{NNN} "{title}" (critical-bug, critical, tag: regression)
108
+ ```
109
+
110
+ ### 6. Execute actions
111
+
112
+ #### Autonomous mode (default)
113
+
114
+ Execute all proposed actions immediately:
115
+
116
+ #### Supervised mode (`--supervised`)
117
+
118
+ Present each action individually and wait for user confirmation:
119
+ - **Accept**: execute the action
120
+ - **Reject**: skip the action, leave the feedback in `new/`
121
+ - **Modify**: let the user change the proposed action before executing
122
+
123
+ #### For each triage action:
124
+
125
+ **Creating a backlog item:**
126
+ 1. Scan ALL `.product/backlogs/` subdirectories for highest existing BL-xxx number
127
+ 2. Assign next sequential ID (zero-padded to 3 digits)
128
+ 3. Read `.product/_templates/backlog.tpl.md` for the schema
129
+ 4. Create backlog file at `.product/backlogs/open/BL-{NNN}.md`:
130
+ - Replace `{{id}}` with `BL-{NNN}`
131
+ - Replace `{{title}}` with the synthesized title from the cluster
132
+ - Replace `{{category}}` with the determined category
133
+ - Replace `{{priority}}` with the proposed priority
134
+ - Replace `{{created}}` and `{{updated}}` with today's date
135
+ - Replace `{{owner}}` with git user name or `unknown`
136
+ - Set `feedbacks:` array with all feedback IDs in the cluster
137
+ - Replace `{{body}}` with a synthesized description of the problem from the cluster
138
+ 5. For each feedback in the cluster:
139
+ - Move file from `feedbacks/new/` to `feedbacks/triaged/`
140
+ - Update frontmatter: `status: "triaged"`, `updated: today`
141
+ - Add the backlog ID to `linked_to.backlog[]`
142
+
143
+ **Excluding a feedback:**
144
+ 1. Move file from `feedbacks/new/` to `feedbacks/excluded/`
145
+ 2. Update frontmatter: `status: "excluded"`, `updated: today`
146
+ 3. Set `exclusion_reason` to the specific reason (e.g., "duplicate-resolved", "noise", "out-of-scope")
147
+
148
+ **Handling a regression:**
149
+ 1. Create a backlog item (same as above) with:
150
+ - `category: "critical-bug"`
151
+ - `priority: "critical"`
152
+ - `tags: ["regression"]`
153
+ 2. Move the feedback to `triaged/` with the backlog link
154
+
155
+ ### 7. Update index
156
+
157
+ Read `.product/index.yaml` and update:
158
+ - Feedback counts by status (decrement `new`, increment `triaged`/`excluded` as appropriate)
159
+ - Backlog counts (increment `open` for each new backlog)
160
+ - Category distributions
161
+ - Recalculate `metrics.feedback_to_backlog_rate`
162
+ - Update `updated` timestamp
163
+
164
+ Write the updated index back.
165
+
166
+ ### 8. Output report
167
+
168
+ ```markdown
169
+ ## Triage Complete
170
+
171
+ **Processed**: {count} feedbacks
172
+ **Created**: {count} backlog item(s)
173
+ **Excluded**: {count} feedback(s)
174
+ **Regressions**: {count} detected
175
+
176
+ | Feedback | Action | Result |
177
+ |----------|--------|--------|
178
+ | FB-xxx | Grouped → BL-{NNN} | triaged/ |
179
+ | FB-yyy | Grouped → BL-{NNN} | triaged/ |
180
+ | FB-zzz | Standalone → BL-{NNN} | triaged/ |
181
+ | FB-aaa | Excluded ({reason}) | excluded/ |
182
+
183
+ **Next**: Review backlogs with `/product.backlog` or promote with `/product.promote BL-xxx`.
184
+ ```
185
+
186
+ ## Error Handling
187
+
188
+ - No feedbacks in `new/` → INFO, stop gracefully
189
+ - `.product/` missing → ERROR with init instructions
190
+ - Batch > 30 items → WARN, process first 30, instruct to re-run
191
+ - Feature file not found during regression check → skip regression detection for that feedback, note in report
192
+ - Feedback file cannot be parsed → WARN, skip, leave in `new/`
193
+
194
+ ## Rules
195
+
196
+ - ALWAYS use semantic similarity for clustering — NEVER keyword matching
197
+ - ALWAYS scan ALL backlogs/ and feedbacks/ subdirs for ID assignment — NEVER reuse IDs
198
+ - ALWAYS update bidirectional links (feedback → backlog AND backlog → feedbacks)
199
+ - ALWAYS move files to new directories as state transitions — NEVER just update frontmatter status without moving
200
+ - ALWAYS update `index.yaml` after all actions
201
+ - NEVER modify resolved feedbacks (read-only context)
202
+ - NEVER modify existing backlog items (read-only context)
203
+ - Category MUST be one of: `critical-bug`, `bug`, `optimization`, `evolution`, `new-feature`
204
+ - Priority MUST be one of: `low`, `medium`, `high`, `critical`
205
+ - In supervised mode, respect user decisions without argument
@@ -0,0 +1,21 @@
1
+ ---
2
+ id: "{{id}}"
3
+ title: "{{title}}"
4
+ status: "open"
5
+ category: "{{category}}"
6
+ priority: "{{priority}}"
7
+ created: "{{created}}"
8
+ updated: "{{updated}}"
9
+ owner: "{{owner}}"
10
+ feedbacks: []
11
+ features: []
12
+ tags: []
13
+ promotion:
14
+ promoted_date: ""
15
+ feature_id: ""
16
+ cancellation:
17
+ cancelled_date: ""
18
+ reason: ""
19
+ ---
20
+
21
+ {{body}}