jettypod 4.4.82 → 4.4.84
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/apps/dashboard/components/DragContext.tsx +136 -7
- package/apps/dashboard/components/DraggableCard.tsx +34 -2
- package/apps/dashboard/components/KanbanBoard.tsx +201 -97
- package/apps/dashboard/components/PlaceholderCard.tsx +30 -0
- package/apps/dashboard/components/RealTimeKanbanWrapper.tsx +6 -3
- package/apps/dashboard/lib/db.ts +9 -0
- package/hooks/post-checkout +11 -1
- package/jettypod.js +25 -20
- package/lib/database.js +31 -0
- package/lib/db-export.js +20 -17
- package/lib/db-import.js +120 -1
- package/lib/git-hooks/pre-commit +56 -16
- package/package.json +1 -1
- package/skills-templates/bug-planning/SKILL.md +1 -1
- package/skills-templates/chore-planning/SKILL.md +1 -1
- package/skills-templates/epic-planning/SKILL.md +1 -1
- package/skills-templates/feature-planning/SKILL.md +1 -42
- package/skills-templates/plan-routing/SKILL.md +188 -0
- package/skills-templates/simple-improvement/SKILL.md +1 -1
package/lib/db-export.js
CHANGED
|
@@ -83,17 +83,16 @@ async function exportWorkDb() {
|
|
|
83
83
|
try {
|
|
84
84
|
fs.writeFileSync(outputPath, JSON.stringify(data, null, 2), 'utf8');
|
|
85
85
|
} catch (err) {
|
|
86
|
-
//
|
|
87
|
-
|
|
86
|
+
// Throw error to block commit - snapshot backup is critical
|
|
87
|
+
let message = 'Failed to export work.json';
|
|
88
88
|
if (err.code === 'EACCES') {
|
|
89
|
-
|
|
89
|
+
message += ': Permission denied - check directory permissions';
|
|
90
90
|
} else if (err.code === 'ENOSPC') {
|
|
91
|
-
|
|
91
|
+
message += ': No space left on device';
|
|
92
92
|
} else {
|
|
93
|
-
|
|
93
|
+
message += `: ${err.message}`;
|
|
94
94
|
}
|
|
95
|
-
|
|
96
|
-
// Return path anyway so commit can continue
|
|
95
|
+
throw new Error(message);
|
|
97
96
|
}
|
|
98
97
|
|
|
99
98
|
return outputPath;
|
|
@@ -115,15 +114,16 @@ async function exportDatabaseDb() {
|
|
|
115
114
|
try {
|
|
116
115
|
fs.writeFileSync(outputPath, JSON.stringify({}, null, 2), 'utf8');
|
|
117
116
|
} catch (err) {
|
|
118
|
-
|
|
117
|
+
// Throw error to block commit - snapshot backup is critical
|
|
118
|
+
let message = 'Failed to export database.json';
|
|
119
119
|
if (err.code === 'EACCES') {
|
|
120
|
-
|
|
120
|
+
message += ': Permission denied - check directory permissions';
|
|
121
121
|
} else if (err.code === 'ENOSPC') {
|
|
122
|
-
|
|
122
|
+
message += ': No space left on device';
|
|
123
123
|
} else {
|
|
124
|
-
|
|
124
|
+
message += `: ${err.message}`;
|
|
125
125
|
}
|
|
126
|
-
|
|
126
|
+
throw new Error(message);
|
|
127
127
|
}
|
|
128
128
|
return outputPath;
|
|
129
129
|
}
|
|
@@ -142,15 +142,18 @@ async function exportDatabaseDb() {
|
|
|
142
142
|
try {
|
|
143
143
|
fs.writeFileSync(outputPath, JSON.stringify(data, null, 2), 'utf8');
|
|
144
144
|
} catch (writeErr) {
|
|
145
|
-
|
|
145
|
+
// Throw error to block commit - snapshot backup is critical
|
|
146
|
+
let message = 'Failed to export database.json';
|
|
146
147
|
if (writeErr.code === 'EACCES') {
|
|
147
|
-
|
|
148
|
+
message += ': Permission denied - check directory permissions';
|
|
148
149
|
} else if (writeErr.code === 'ENOSPC') {
|
|
149
|
-
|
|
150
|
+
message += ': No space left on device';
|
|
150
151
|
} else {
|
|
151
|
-
|
|
152
|
+
message += `: ${writeErr.message}`;
|
|
152
153
|
}
|
|
153
|
-
|
|
154
|
+
db.close();
|
|
155
|
+
reject(new Error(message));
|
|
156
|
+
return;
|
|
154
157
|
}
|
|
155
158
|
|
|
156
159
|
db.close((closeErr) => {
|
package/lib/db-import.js
CHANGED
|
@@ -2,6 +2,109 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { getDb, getJettypodDir } = require('./database');
|
|
4
4
|
|
|
5
|
+
// Valid values for work_items fields
|
|
6
|
+
const VALID_TYPES = ['epic', 'feature', 'chore', 'bug'];
|
|
7
|
+
const VALID_STATUSES = ['backlog', 'todo', 'in_progress', 'done', 'cancelled'];
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Validate a single work item against the schema
|
|
11
|
+
* @param {Object} item - Work item to validate
|
|
12
|
+
* @param {number} index - Index in array for error messages
|
|
13
|
+
* @returns {{valid: boolean, errors: string[]}}
|
|
14
|
+
*/
|
|
15
|
+
function validateWorkItem(item, index) {
|
|
16
|
+
const errors = [];
|
|
17
|
+
|
|
18
|
+
if (typeof item !== 'object' || item === null) {
|
|
19
|
+
return { valid: false, errors: [`Item ${index}: must be an object`] };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Required: id must be a number
|
|
23
|
+
if (item.id === undefined || item.id === null) {
|
|
24
|
+
errors.push(`Item ${index}: missing required field 'id'`);
|
|
25
|
+
} else if (typeof item.id !== 'number' || !Number.isInteger(item.id)) {
|
|
26
|
+
errors.push(`Item ${index}: 'id' must be an integer`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Required: type must be a valid string
|
|
30
|
+
if (item.type === undefined || item.type === null) {
|
|
31
|
+
errors.push(`Item ${index}: missing required field 'type'`);
|
|
32
|
+
} else if (typeof item.type !== 'string') {
|
|
33
|
+
errors.push(`Item ${index}: 'type' must be a string`);
|
|
34
|
+
} else if (!VALID_TYPES.includes(item.type)) {
|
|
35
|
+
errors.push(`Item ${index}: 'type' must be one of: ${VALID_TYPES.join(', ')}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Required: title must be a string
|
|
39
|
+
if (item.title === undefined || item.title === null) {
|
|
40
|
+
errors.push(`Item ${index}: missing required field 'title'`);
|
|
41
|
+
} else if (typeof item.title !== 'string') {
|
|
42
|
+
errors.push(`Item ${index}: 'title' must be a string`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Optional: status must be valid if present
|
|
46
|
+
if (item.status !== undefined && item.status !== null) {
|
|
47
|
+
if (typeof item.status !== 'string') {
|
|
48
|
+
errors.push(`Item ${index}: 'status' must be a string`);
|
|
49
|
+
} else if (!VALID_STATUSES.includes(item.status)) {
|
|
50
|
+
errors.push(`Item ${index}: 'status' must be one of: ${VALID_STATUSES.join(', ')}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Optional: parent_id must be integer if present
|
|
55
|
+
if (item.parent_id !== undefined && item.parent_id !== null) {
|
|
56
|
+
if (typeof item.parent_id !== 'number' || !Number.isInteger(item.parent_id)) {
|
|
57
|
+
errors.push(`Item ${index}: 'parent_id' must be an integer`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Optional: epic_id must be integer if present
|
|
62
|
+
if (item.epic_id !== undefined && item.epic_id !== null) {
|
|
63
|
+
if (typeof item.epic_id !== 'number' || !Number.isInteger(item.epic_id)) {
|
|
64
|
+
errors.push(`Item ${index}: 'epic_id' must be an integer`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return { valid: errors.length === 0, errors };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Validate work.json data structure and content
|
|
73
|
+
* @param {Object} data - Parsed JSON data
|
|
74
|
+
* @returns {{valid: boolean, errors: string[]}}
|
|
75
|
+
*/
|
|
76
|
+
function validateWorkJson(data) {
|
|
77
|
+
const errors = [];
|
|
78
|
+
|
|
79
|
+
if (typeof data !== 'object' || data === null) {
|
|
80
|
+
return { valid: false, errors: ['Data must be an object'] };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// work_items must be present and an array
|
|
84
|
+
if (!data.work_items) {
|
|
85
|
+
return { valid: false, errors: ['Missing required field: work_items'] };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!Array.isArray(data.work_items)) {
|
|
89
|
+
return { valid: false, errors: ['work_items must be an array'] };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Validate each work item
|
|
93
|
+
data.work_items.forEach((item, index) => {
|
|
94
|
+
const result = validateWorkItem(item, index);
|
|
95
|
+
errors.push(...result.errors);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Check for duplicate IDs
|
|
99
|
+
const ids = data.work_items.map(item => item.id).filter(id => id !== undefined);
|
|
100
|
+
const duplicates = ids.filter((id, index) => ids.indexOf(id) !== index);
|
|
101
|
+
if (duplicates.length > 0) {
|
|
102
|
+
errors.push(`Duplicate work item IDs found: ${[...new Set(duplicates)].join(', ')}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return { valid: errors.length === 0, errors };
|
|
106
|
+
}
|
|
107
|
+
|
|
5
108
|
/**
|
|
6
109
|
* Import tables from JSON structure into a database
|
|
7
110
|
* @param {sqlite3.Database} db - Database connection
|
|
@@ -86,6 +189,18 @@ async function importWorkDb() {
|
|
|
86
189
|
const jsonContent = fs.readFileSync(jsonPath, 'utf8');
|
|
87
190
|
const data = JSON.parse(jsonContent);
|
|
88
191
|
|
|
192
|
+
// Validate schema before importing
|
|
193
|
+
const validation = validateWorkJson(data);
|
|
194
|
+
if (!validation.valid) {
|
|
195
|
+
console.error('Post-checkout hook warning: work.json schema validation failed');
|
|
196
|
+
validation.errors.slice(0, 5).forEach(err => console.error(` - ${err}`));
|
|
197
|
+
if (validation.errors.length > 5) {
|
|
198
|
+
console.error(` ... and ${validation.errors.length - 5} more errors`);
|
|
199
|
+
}
|
|
200
|
+
console.error(' Database will remain in previous state');
|
|
201
|
+
return jsonPath;
|
|
202
|
+
}
|
|
203
|
+
|
|
89
204
|
const db = getDb();
|
|
90
205
|
await importTables(db, data);
|
|
91
206
|
|
|
@@ -189,5 +304,9 @@ async function importAll() {
|
|
|
189
304
|
module.exports = {
|
|
190
305
|
importWorkDb,
|
|
191
306
|
importDatabaseDb,
|
|
192
|
-
importAll
|
|
307
|
+
importAll,
|
|
308
|
+
validateWorkJson,
|
|
309
|
+
validateWorkItem,
|
|
310
|
+
VALID_TYPES,
|
|
311
|
+
VALID_STATUSES
|
|
193
312
|
};
|
package/lib/git-hooks/pre-commit
CHANGED
|
@@ -55,23 +55,63 @@ if (!checkBranchRestriction()) {
|
|
|
55
55
|
process.exit(1);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
58
|
+
// Export database snapshots (runs for all commits where .jettypod exists)
|
|
59
|
+
async function exportSnapshots() {
|
|
60
|
+
const jettypodDir = path.join(process.cwd(), '.jettypod');
|
|
61
|
+
if (!fs.existsSync(jettypodDir)) {
|
|
62
|
+
return; // No JettyPod directory, skip export
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log('\n📸 Exporting database snapshots...\n');
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
try {
|
|
68
|
+
const { exportAll } = require('../db-export');
|
|
69
|
+
const paths = await exportAll();
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
// Stage the snapshot files
|
|
72
|
+
execSync(`git add "${paths.work}" "${paths.database}"`, {
|
|
73
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
74
|
+
});
|
|
70
75
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
console.log('✅ Snapshots exported and staged\n');
|
|
77
|
+
} catch (err) {
|
|
78
|
+
console.error('');
|
|
79
|
+
console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
80
|
+
console.error('❌ Snapshot export failed! Commit blocked.');
|
|
81
|
+
console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
82
|
+
console.error('');
|
|
83
|
+
console.error(`Error: ${err.message}`);
|
|
84
|
+
console.error('');
|
|
85
|
+
console.error('This prevents data loss - your work items must be backed up.');
|
|
86
|
+
console.error('Check disk space and directory permissions.');
|
|
87
|
+
console.error('');
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
77
90
|
}
|
|
91
|
+
|
|
92
|
+
// Main async flow
|
|
93
|
+
(async () => {
|
|
94
|
+
// Export snapshots first (before tests, so they're included in commit)
|
|
95
|
+
await exportSnapshots();
|
|
96
|
+
|
|
97
|
+
// Check if we're in a real project (not a test directory)
|
|
98
|
+
const packageJsonPath = path.join(process.cwd(), 'package.json');
|
|
99
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
100
|
+
// Skip tests in test directories
|
|
101
|
+
process.exit(0);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
console.log('🧪 Running tests before commit...\n');
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
// Run tests
|
|
108
|
+
execSync('npm test', { stdio: 'inherit' });
|
|
109
|
+
|
|
110
|
+
console.log('\n✅ Tests passed! Proceeding with commit.\n');
|
|
111
|
+
process.exit(0);
|
|
112
|
+
} catch (err) {
|
|
113
|
+
console.log('\n❌ Tests failed! Commit blocked.\n');
|
|
114
|
+
console.log('Fix the failing tests or use --no-verify to skip this check.\n');
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bug-planning
|
|
3
|
-
description: Guide structured bug investigation with symptom capture, hypothesis testing, and root cause identification.
|
|
3
|
+
description: Guide structured bug investigation with symptom capture, hypothesis testing, and root cause identification. Invoked by plan-routing when user reports a bug, mentions unexpected behavior, or describes something broken. (project)
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Bug Planning Skill
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: chore-planning
|
|
3
|
-
description: Guide standalone chore planning with automatic type classification and routing to chore-mode.
|
|
3
|
+
description: Guide standalone chore planning with automatic type classification and routing to chore-mode. Invoked by plan-routing for substantial technical work - refactoring, infrastructure, migrations, or enhancements where the implementation approach is obvious. (project)
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Chore Planning Skill
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: epic-planning
|
|
3
|
-
description: Guide epic planning with feature brainstorming and optional architectural decision prototyping.
|
|
3
|
+
description: Guide epic planning with feature brainstorming and optional architectural decision prototyping. Invoked by plan-routing for large multi-feature initiatives that need to be broken down into features. (project)
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Epic Planning Skill
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: feature-planning
|
|
3
|
-
description: Guide feature planning with UX approach exploration and BDD scenario generation.
|
|
3
|
+
description: Guide feature planning with UX approach exploration and BDD scenario generation. Invoked by plan-routing when implementing NEW user-facing behavior that requires UX decisions (multiple valid approaches to explore). (project)
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Feature Planning Skill
|
|
@@ -63,49 +63,8 @@ jettypod workflow start feature-planning <feature-id>
|
|
|
63
63
|
|
|
64
64
|
This creates an execution record for session resume.
|
|
65
65
|
|
|
66
|
-
### Step 1B: Route Simple Improvements
|
|
67
|
-
|
|
68
|
-
**CRITICAL:** Before proceeding with full feature planning, determine if this is a simple improvement.
|
|
69
|
-
|
|
70
|
-
**Ask the user:**
|
|
71
|
-
|
|
72
|
-
```
|
|
73
|
-
Is this:
|
|
74
|
-
1. **Simple improvement** - A basic enhancement to existing functionality (e.g., copy change, styling tweak, minor behavior adjustment)
|
|
75
|
-
2. **New functionality** - Adding new capabilities, even if small
|
|
76
|
-
|
|
77
|
-
Simple improvements skip the full feature planning workflow and use a lightweight process.
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
**⚡ WAIT for user response.**
|
|
81
|
-
|
|
82
|
-
**If user says "simple improvement" (or 1):**
|
|
83
|
-
|
|
84
|
-
Display:
|
|
85
|
-
```
|
|
86
|
-
This is a simple improvement. Routing to the lightweight simple-improvement workflow...
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
**Then IMMEDIATELY invoke simple-improvement using the Skill tool:**
|
|
90
|
-
```
|
|
91
|
-
Use the Skill tool with skill: "simple-improvement"
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
**Feature-planning skill ends here for simple improvements.** The simple-improvement skill takes over.
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
**If user says "new functionality" (or 2):**
|
|
99
|
-
|
|
100
|
-
Display:
|
|
101
|
-
```
|
|
102
|
-
Got it - this is new functionality. Let's explore the best approach...
|
|
103
|
-
```
|
|
104
|
-
|
|
105
66
|
**Proceed to Step 2** (or Step 3 if this is a standalone feature with no parent epic).
|
|
106
67
|
|
|
107
|
-
---
|
|
108
|
-
|
|
109
68
|
### Step 2: Check Epic Architectural Decisions
|
|
110
69
|
|
|
111
70
|
**Skip this step and proceed to Step 3 if `PARENT_EPIC_ID` from Step 1 is null (standalone feature).**
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plan-routing
|
|
3
|
+
description: Route work requests to the appropriate planning skill. Use when user describes work they want to do - "build X", "fix Y", "add Z", "plan W". Analyzes intent and complexity to route to bug-planning, chore-planning, feature-planning, epic-planning, or simple-improvement. (project)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Plan Routing Skill
|
|
7
|
+
|
|
8
|
+
Routes user work requests to the correct planning workflow with minimal friction.
|
|
9
|
+
|
|
10
|
+
## Instructions
|
|
11
|
+
|
|
12
|
+
When this skill is activated, you are helping route a user's work request to the appropriate planning skill. Follow this structured approach:
|
|
13
|
+
|
|
14
|
+
### Step 1: Extract Intent Signals
|
|
15
|
+
|
|
16
|
+
From the user's request, identify work type and complexity signals:
|
|
17
|
+
|
|
18
|
+
**Work type signals:**
|
|
19
|
+
| Signal Words | Likely Route |
|
|
20
|
+
|--------------|--------------|
|
|
21
|
+
| fix, bug, broken, crash, error, not working, regression | bug-planning |
|
|
22
|
+
| refactor, rename, move, clean up, upgrade, migrate, infrastructure | chore-planning |
|
|
23
|
+
| add, build, create, implement, new feature, capability, workflow | feature-planning |
|
|
24
|
+
| epic, initiative, project, roadmap, multi-feature | epic-planning |
|
|
25
|
+
| tweak, change, update, adjust + small scope | simple-improvement |
|
|
26
|
+
|
|
27
|
+
**Complexity signals:**
|
|
28
|
+
| Signal | Indicates |
|
|
29
|
+
|--------|-----------|
|
|
30
|
+
| "quick", "small", "just", "simple", "tweak" | Lower complexity |
|
|
31
|
+
| "feature", "workflow", "experience", "redesign" | Higher complexity |
|
|
32
|
+
| References specific file/function | Lower complexity |
|
|
33
|
+
| Describes user-facing behavior change | Higher complexity |
|
|
34
|
+
|
|
35
|
+
### Step 2: Gather Context (Silent - No Questions)
|
|
36
|
+
|
|
37
|
+
Before routing, quickly probe the codebase for context. **Do NOT ask the user for this information.**
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Check for related existing code
|
|
41
|
+
jettypod impact "<key-term-from-request>"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Check for existing work items
|
|
46
|
+
jettypod backlog | grep -i "<key-term>"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Assess from results:**
|
|
50
|
+
- Existing code? → Likely modification vs creation
|
|
51
|
+
- Related work items? → May already be planned
|
|
52
|
+
- How many files affected? → Complexity indicator
|
|
53
|
+
|
|
54
|
+
### Step 3: Route with Stated Assumption
|
|
55
|
+
|
|
56
|
+
**DO NOT ASK a routing question.** State your routing decision with reasoning.
|
|
57
|
+
|
|
58
|
+
## Routing Decision Tree
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
User request
|
|
62
|
+
│
|
|
63
|
+
▼
|
|
64
|
+
Contains bug/fix/broken/error signals?
|
|
65
|
+
├─► Yes → bug-planning
|
|
66
|
+
│
|
|
67
|
+
▼
|
|
68
|
+
Describes large multi-feature initiative?
|
|
69
|
+
├─► Yes → epic-planning
|
|
70
|
+
│
|
|
71
|
+
▼
|
|
72
|
+
Does this need UX exploration?
|
|
73
|
+
(Multiple valid approaches? User-facing behavior with design choices?)
|
|
74
|
+
├─► Yes → feature-planning
|
|
75
|
+
│
|
|
76
|
+
▼
|
|
77
|
+
Is this substantial technical work?
|
|
78
|
+
(Refactoring, infrastructure, migrations, multi-file changes)
|
|
79
|
+
├─► Yes → chore-planning
|
|
80
|
+
│
|
|
81
|
+
▼
|
|
82
|
+
Is this a simple, obvious change?
|
|
83
|
+
(Copy, styling, config, minor behavior tweak, one clear approach)
|
|
84
|
+
└─► Yes → simple-improvement
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Route Definitions
|
|
88
|
+
|
|
89
|
+
| Route | When to Use | Progression |
|
|
90
|
+
|-------|-------------|-------------|
|
|
91
|
+
| **bug-planning** | Something is broken/not working as expected | Investigation → fix |
|
|
92
|
+
| **epic-planning** | Large initiative spanning multiple features | Break down → plan features |
|
|
93
|
+
| **feature-planning** | New user-facing behavior with UX decisions to make | UX exploration → BDD → speed → stable → production |
|
|
94
|
+
| **chore-planning** | Substantial technical work, clear implementation | speed → stable → production |
|
|
95
|
+
| **simple-improvement** | Obvious change, no UX decisions, small scope | Direct implementation |
|
|
96
|
+
|
|
97
|
+
## Routing Examples
|
|
98
|
+
|
|
99
|
+
**→ bug-planning**
|
|
100
|
+
- "The login button doesn't work on mobile"
|
|
101
|
+
- "Getting a crash when I save"
|
|
102
|
+
- "Users are seeing a 500 error"
|
|
103
|
+
|
|
104
|
+
**→ epic-planning**
|
|
105
|
+
- "We need a full authentication system"
|
|
106
|
+
- "Build out the reporting dashboard"
|
|
107
|
+
- "Plan the v2 API migration"
|
|
108
|
+
|
|
109
|
+
**→ feature-planning**
|
|
110
|
+
- "Add drag-and-drop reordering for cards"
|
|
111
|
+
- "Implement user notifications"
|
|
112
|
+
- "Build a search feature"
|
|
113
|
+
|
|
114
|
+
*(Multiple valid UX approaches exist)*
|
|
115
|
+
|
|
116
|
+
**→ chore-planning**
|
|
117
|
+
- "Refactor the auth module to use the new pattern"
|
|
118
|
+
- "Migrate from Moment.js to date-fns"
|
|
119
|
+
- "Add TypeScript to the utils folder"
|
|
120
|
+
- "Set up CI/CD pipeline"
|
|
121
|
+
|
|
122
|
+
*(Technical work, obvious approach, but substantial)*
|
|
123
|
+
|
|
124
|
+
**→ simple-improvement**
|
|
125
|
+
- "Change the button text from 'Submit' to 'Save'"
|
|
126
|
+
- "Make the error message more descriptive"
|
|
127
|
+
- "Add a loading spinner to the save button"
|
|
128
|
+
- "Change the header color to blue"
|
|
129
|
+
- "Add a tooltip to the settings icon"
|
|
130
|
+
|
|
131
|
+
*(One obvious implementation, no UX exploration needed, just do it)*
|
|
132
|
+
|
|
133
|
+
## Stating Your Routing Decision
|
|
134
|
+
|
|
135
|
+
**Bug:**
|
|
136
|
+
```
|
|
137
|
+
Sounds like a bug - [X] isn't working as expected. Let me help you investigate.
|
|
138
|
+
```
|
|
139
|
+
Then invoke bug-planning skill.
|
|
140
|
+
|
|
141
|
+
**Epic:**
|
|
142
|
+
```
|
|
143
|
+
This is a larger initiative with multiple features. Let's break it down.
|
|
144
|
+
```
|
|
145
|
+
Then invoke epic-planning skill.
|
|
146
|
+
|
|
147
|
+
**Feature:**
|
|
148
|
+
```
|
|
149
|
+
This adds new user-facing behavior with some design choices to explore. Let me suggest a few approaches.
|
|
150
|
+
```
|
|
151
|
+
Then invoke feature-planning skill.
|
|
152
|
+
|
|
153
|
+
**Chore:**
|
|
154
|
+
```
|
|
155
|
+
This is technical work with a clear implementation path. Let me help you plan it out.
|
|
156
|
+
```
|
|
157
|
+
Then invoke chore-planning skill.
|
|
158
|
+
|
|
159
|
+
**Simple improvement:**
|
|
160
|
+
```
|
|
161
|
+
This is a straightforward change. Let me implement it.
|
|
162
|
+
```
|
|
163
|
+
Then invoke simple-improvement skill.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
**If genuinely ambiguous (rare - should be <20% of cases):**
|
|
168
|
+
```
|
|
169
|
+
I could approach "[brief description]" as:
|
|
170
|
+
- A **simple improvement** - just implement the obvious solution
|
|
171
|
+
- A **feature** - explore a few UX approaches first
|
|
172
|
+
|
|
173
|
+
Which feels right?
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Only ask when you truly cannot decide based on signals and context.
|
|
177
|
+
|
|
178
|
+
### Step 4: Invoke Target Skill
|
|
179
|
+
|
|
180
|
+
After stating your routing decision, immediately invoke the appropriate skill using the Skill tool:
|
|
181
|
+
- `bug-planning`
|
|
182
|
+
- `chore-planning`
|
|
183
|
+
- `feature-planning`
|
|
184
|
+
- `epic-planning`
|
|
185
|
+
- `simple-improvement`
|
|
186
|
+
|
|
187
|
+
**This skill ends after invocation.** The target skill takes over.
|
|
188
|
+
# Stable mode: Verified ambiguous request handling exists
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: simple-improvement
|
|
3
|
-
description: Guide implementation of simple improvements to existing functionality.
|
|
3
|
+
description: Guide implementation of simple improvements to existing functionality. Invoked by plan-routing for straightforward changes like copy changes, styling tweaks, or minor behavior adjustments where the implementation is obvious. (project)
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Simple Improvement Skill
|