jettypod 4.4.116 → 4.4.120

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.
Files changed (162) hide show
  1. package/.env +7 -0
  2. package/apps/dashboard/app/api/claude/[workItemId]/message/route.ts +124 -48
  3. package/apps/dashboard/app/api/claude/[workItemId]/route.ts +171 -58
  4. package/apps/dashboard/app/api/claude/sessions/[sessionId]/message/route.ts +161 -10
  5. package/apps/dashboard/app/api/tests/run/stream/route.ts +13 -1
  6. package/apps/dashboard/app/api/usage/route.ts +17 -0
  7. package/apps/dashboard/app/api/work/[id]/route.ts +35 -0
  8. package/apps/dashboard/app/api/work/[id]/status/route.ts +43 -1
  9. package/apps/dashboard/app/connect-claude/page.tsx +24 -0
  10. package/apps/dashboard/app/decision/[id]/page.tsx +14 -14
  11. package/apps/dashboard/app/demo/gates/page.tsx +42 -42
  12. package/apps/dashboard/app/design-system/page.tsx +868 -0
  13. package/apps/dashboard/app/globals.css +6 -2
  14. package/apps/dashboard/app/install-claude/page.tsx +9 -7
  15. package/apps/dashboard/app/layout.tsx +17 -5
  16. package/apps/dashboard/app/login/page.tsx +250 -0
  17. package/apps/dashboard/app/page.tsx +11 -9
  18. package/apps/dashboard/app/settings/page.tsx +4 -2
  19. package/apps/dashboard/app/signup/page.tsx +245 -0
  20. package/apps/dashboard/app/subscribe/page.tsx +11 -0
  21. package/apps/dashboard/app/welcome/page.tsx +24 -1
  22. package/apps/dashboard/app/work/[id]/page.tsx +34 -50
  23. package/apps/dashboard/components/AppShell.tsx +95 -55
  24. package/apps/dashboard/components/CardMenu.tsx +56 -13
  25. package/apps/dashboard/components/ClaudePanel.tsx +301 -582
  26. package/apps/dashboard/components/ClaudePanelInput.tsx +23 -14
  27. package/apps/dashboard/components/ConnectClaudeScreen.tsx +210 -0
  28. package/apps/dashboard/components/CopyableId.tsx +3 -3
  29. package/apps/dashboard/components/DetailReviewActions.tsx +109 -0
  30. package/apps/dashboard/components/DragContext.tsx +75 -65
  31. package/apps/dashboard/components/DraggableCard.tsx +6 -46
  32. package/apps/dashboard/components/DropZone.tsx +2 -2
  33. package/apps/dashboard/components/EditableDetailDescription.tsx +1 -1
  34. package/apps/dashboard/components/EditableTitle.tsx +26 -6
  35. package/apps/dashboard/components/ElapsedTimer.tsx +54 -0
  36. package/apps/dashboard/components/EpicGroup.tsx +329 -0
  37. package/apps/dashboard/components/GateCard.tsx +100 -16
  38. package/apps/dashboard/components/GateChoiceCard.tsx +15 -17
  39. package/apps/dashboard/components/InstallClaudeScreen.tsx +140 -51
  40. package/apps/dashboard/components/JettyLoader.tsx +38 -0
  41. package/apps/dashboard/components/KanbanBoard.tsx +147 -766
  42. package/apps/dashboard/components/KanbanCard.tsx +506 -0
  43. package/apps/dashboard/components/LazyMarkdown.tsx +12 -0
  44. package/apps/dashboard/components/MainNav.tsx +20 -54
  45. package/apps/dashboard/components/MessageBlock.tsx +391 -0
  46. package/apps/dashboard/components/ModeStartCard.tsx +15 -15
  47. package/apps/dashboard/components/OnboardingWelcome.tsx +214 -0
  48. package/apps/dashboard/components/PlaceholderCard.tsx +11 -21
  49. package/apps/dashboard/components/ProjectSwitcher.tsx +36 -8
  50. package/apps/dashboard/components/PrototypeTimeline.tsx +25 -25
  51. package/apps/dashboard/components/RealTimeKanbanWrapper.tsx +265 -301
  52. package/apps/dashboard/components/RealTimeTestsWrapper.tsx +97 -74
  53. package/apps/dashboard/components/ReviewFooter.tsx +141 -0
  54. package/apps/dashboard/components/SessionList.tsx +19 -18
  55. package/apps/dashboard/components/SubscribeContent.tsx +206 -0
  56. package/apps/dashboard/components/TestTree.tsx +15 -14
  57. package/apps/dashboard/components/TipCard.tsx +177 -0
  58. package/apps/dashboard/components/Toast.tsx +5 -5
  59. package/apps/dashboard/components/TypeIcon.tsx +56 -0
  60. package/apps/dashboard/components/UpgradeBanner.tsx +30 -0
  61. package/apps/dashboard/components/WaveCompletionAnimation.tsx +61 -62
  62. package/apps/dashboard/components/WelcomeScreen.tsx +25 -27
  63. package/apps/dashboard/components/WorkItemHeader.tsx +4 -4
  64. package/apps/dashboard/components/WorkItemTree.tsx +9 -28
  65. package/apps/dashboard/components/settings/AccountSection.tsx +169 -0
  66. package/apps/dashboard/components/settings/EnvVarsSection.tsx +54 -79
  67. package/apps/dashboard/components/settings/GeneralSection.tsx +26 -31
  68. package/apps/dashboard/components/settings/SettingsLayout.tsx +4 -4
  69. package/apps/dashboard/components/ui/Button.tsx +104 -0
  70. package/apps/dashboard/components/ui/Input.tsx +78 -0
  71. package/apps/dashboard/contexts/ClaudeSessionContext.tsx +408 -105
  72. package/apps/dashboard/contexts/ConnectionStatusContext.tsx +25 -4
  73. package/apps/dashboard/contexts/UsageContext.tsx +155 -0
  74. package/apps/dashboard/contexts/usageHelpers.js +9 -0
  75. package/apps/dashboard/electron/ipc-handlers.js +281 -88
  76. package/apps/dashboard/electron/main.js +691 -131
  77. package/apps/dashboard/electron/preload.js +25 -4
  78. package/apps/dashboard/electron/session-manager.js +163 -0
  79. package/apps/dashboard/electron-builder.config.js +3 -5
  80. package/apps/dashboard/hooks/useKanbanAnimation.ts +29 -0
  81. package/apps/dashboard/hooks/useKanbanUndo.ts +83 -0
  82. package/apps/dashboard/lib/backlog-parser.ts +50 -0
  83. package/apps/dashboard/lib/claude-process-manager.ts +50 -11
  84. package/apps/dashboard/lib/constants.ts +43 -0
  85. package/apps/dashboard/lib/db-bridge.ts +33 -0
  86. package/apps/dashboard/lib/db.ts +136 -20
  87. package/apps/dashboard/lib/kanban-utils.ts +70 -0
  88. package/apps/dashboard/lib/run-migrations.js +27 -2
  89. package/apps/dashboard/lib/session-state-machine.ts +3 -0
  90. package/apps/dashboard/lib/session-stream-manager.ts +144 -38
  91. package/apps/dashboard/lib/shadows.ts +7 -0
  92. package/apps/dashboard/lib/tests.ts +3 -1
  93. package/apps/dashboard/lib/utils.ts +6 -0
  94. package/apps/dashboard/next.config.js +35 -14
  95. package/apps/dashboard/package.json +6 -3
  96. package/apps/dashboard/public/bug-icon.svg +9 -0
  97. package/apps/dashboard/public/buoy-icon.svg +9 -0
  98. package/apps/dashboard/public/fonts/Satoshi-Variable.woff2 +0 -0
  99. package/apps/dashboard/public/fonts/Satoshi-VariableItalic.woff2 +0 -0
  100. package/apps/dashboard/public/in-flight-seagull.svg +9 -0
  101. package/apps/dashboard/public/jetty-icon-loading-alt.svg +11 -0
  102. package/apps/dashboard/public/jetty-icon-loading.svg +11 -0
  103. package/apps/dashboard/public/jettypod_logo.png +0 -0
  104. package/apps/dashboard/public/pier-icon.svg +14 -0
  105. package/apps/dashboard/public/star-icon.svg +9 -0
  106. package/apps/dashboard/public/wrench-icon.svg +9 -0
  107. package/apps/dashboard/scripts/upload-to-r2.js +89 -0
  108. package/apps/dashboard/scripts/ws-server.js +191 -0
  109. package/apps/dashboard/tsconfig.tsbuildinfo +1 -0
  110. package/apps/update-server/package.json +16 -0
  111. package/apps/update-server/schema.sql +31 -0
  112. package/apps/update-server/src/index.ts +1085 -0
  113. package/apps/update-server/tsconfig.json +16 -0
  114. package/apps/update-server/wrangler.toml +35 -0
  115. package/cucumber.js +9 -3
  116. package/docs/COMMAND_REFERENCE.md +34 -0
  117. package/hooks/post-checkout +32 -75
  118. package/hooks/post-merge +111 -10
  119. package/jest.setup.js +1 -0
  120. package/jettypod.js +54 -116
  121. package/lib/chore-taxonomy.js +33 -10
  122. package/lib/database.js +36 -16
  123. package/lib/db-watcher.js +1 -1
  124. package/lib/git-hooks/pre-commit +1 -1
  125. package/lib/jettypod-backup.js +27 -4
  126. package/lib/migrations/027-plan-at-creation-column.js +33 -0
  127. package/lib/migrations/028-ready-for-review-column.js +27 -0
  128. package/lib/migrations/029-remove-autoincrement.js +307 -0
  129. package/lib/migrations/029-rename-corrupted-to-cleaned.js +149 -0
  130. package/lib/migrations/index.js +47 -4
  131. package/lib/schema.js +13 -6
  132. package/lib/seed-onboarding.js +101 -69
  133. package/lib/update-command/index.js +9 -175
  134. package/lib/work-commands/index.js +129 -16
  135. package/lib/work-tracking/index.js +86 -46
  136. package/lib/worktree-diagnostics.js +16 -16
  137. package/lib/worktree-facade.js +1 -1
  138. package/lib/worktree-manager.js +8 -8
  139. package/lib/worktree-reconciler.js +5 -5
  140. package/package.json +9 -2
  141. package/scripts/ndjson-to-cucumber-json.js +152 -0
  142. package/scripts/postinstall.js +25 -0
  143. package/skills-templates/bug-mode/SKILL.md +39 -28
  144. package/skills-templates/bug-planning/SKILL.md +25 -29
  145. package/skills-templates/chore-mode/SKILL.md +131 -68
  146. package/skills-templates/chore-mode/verification.js +51 -10
  147. package/skills-templates/chore-planning/SKILL.md +47 -18
  148. package/skills-templates/epic-planning/SKILL.md +68 -48
  149. package/skills-templates/external-transition/SKILL.md +47 -47
  150. package/skills-templates/feature-planning/SKILL.md +83 -73
  151. package/skills-templates/production-mode/SKILL.md +49 -49
  152. package/skills-templates/request-routing/SKILL.md +27 -14
  153. package/skills-templates/simple-improvement/SKILL.md +68 -44
  154. package/skills-templates/speed-mode/SKILL.md +209 -128
  155. package/skills-templates/stable-mode/SKILL.md +105 -94
  156. package/templates/bdd-guidance.md +139 -0
  157. package/templates/bdd-scaffolding/wait.js +18 -0
  158. package/templates/bdd-scaffolding/world.js +19 -0
  159. package/.jettypod-backup/work.db +0 -0
  160. package/apps/dashboard/app/access-code/page.tsx +0 -110
  161. package/lib/discovery-checkpoint.js +0 -123
  162. package/skills-templates/project-discovery/SKILL.md +0 -372
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Migration: Rename worktree status 'corrupted' to 'cleaned'
3
+ *
4
+ * The 'corrupted' status was misleading — it's the terminal state for worktrees
5
+ * that have been successfully cleaned up, not actually corrupted data.
6
+ * Renaming to 'cleaned' for clarity.
7
+ *
8
+ * SQLite doesn't support ALTER CONSTRAINT, so we recreate the table.
9
+ */
10
+
11
+ module.exports = {
12
+ id: '029-rename-corrupted-to-cleaned',
13
+ description: 'Rename worktree status corrupted to cleaned for clarity',
14
+
15
+ async up(db) {
16
+ return new Promise((resolve, reject) => {
17
+ db.serialize(() => {
18
+ // 1. Update existing records
19
+ db.run(`UPDATE worktrees SET status = 'cleaned' WHERE status = 'corrupted'`, (err) => {
20
+ if (err) return reject(err);
21
+ });
22
+
23
+ // 2. Create new table with updated constraint
24
+ db.run(`
25
+ CREATE TABLE IF NOT EXISTS worktrees_new (
26
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
27
+ work_item_id INTEGER NOT NULL,
28
+ branch_name TEXT NOT NULL,
29
+ worktree_path TEXT NOT NULL,
30
+ status TEXT NOT NULL CHECK(status IN ('active', 'merging', 'merged', 'cleanup_pending', 'cleaned')),
31
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
32
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
33
+ FOREIGN KEY (work_item_id) REFERENCES work_items(id)
34
+ )
35
+ `, (err) => {
36
+ if (err) return reject(err);
37
+ });
38
+
39
+ // 3. Copy data
40
+ db.run(`
41
+ INSERT INTO worktrees_new (id, work_item_id, branch_name, worktree_path, status, created_at, updated_at)
42
+ SELECT id, work_item_id, branch_name, worktree_path, status, created_at, updated_at
43
+ FROM worktrees
44
+ `, (err) => {
45
+ if (err) return reject(err);
46
+ });
47
+
48
+ // 4. Drop old indexes
49
+ db.run('DROP INDEX IF EXISTS idx_worktrees_work_item_id', (err) => {
50
+ if (err) return reject(err);
51
+ });
52
+
53
+ db.run('DROP INDEX IF EXISTS idx_worktrees_status', (err) => {
54
+ if (err) return reject(err);
55
+ });
56
+
57
+ // 5. Drop old table
58
+ db.run('DROP TABLE worktrees', (err) => {
59
+ if (err) return reject(err);
60
+ });
61
+
62
+ // 6. Rename new table
63
+ db.run('ALTER TABLE worktrees_new RENAME TO worktrees', (err) => {
64
+ if (err) return reject(err);
65
+ });
66
+
67
+ // 7. Recreate indexes
68
+ db.run(`
69
+ CREATE INDEX idx_worktrees_work_item_id
70
+ ON worktrees(work_item_id)
71
+ `, (err) => {
72
+ if (err) return reject(err);
73
+ });
74
+
75
+ db.run(`
76
+ CREATE INDEX idx_worktrees_status
77
+ ON worktrees(status)
78
+ `, (err) => {
79
+ if (err) return reject(err);
80
+ resolve();
81
+ });
82
+ });
83
+ });
84
+ },
85
+
86
+ async down(db) {
87
+ return new Promise((resolve, reject) => {
88
+ db.serialize(() => {
89
+ db.run(`UPDATE worktrees SET status = 'corrupted' WHERE status = 'cleaned'`, (err) => {
90
+ if (err) return reject(err);
91
+ });
92
+
93
+ db.run(`
94
+ CREATE TABLE IF NOT EXISTS worktrees_new (
95
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
96
+ work_item_id INTEGER NOT NULL,
97
+ branch_name TEXT NOT NULL,
98
+ worktree_path TEXT NOT NULL,
99
+ status TEXT NOT NULL CHECK(status IN ('active', 'merging', 'merged', 'cleanup_pending', 'corrupted')),
100
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
101
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
102
+ FOREIGN KEY (work_item_id) REFERENCES work_items(id)
103
+ )
104
+ `, (err) => {
105
+ if (err) return reject(err);
106
+ });
107
+
108
+ db.run(`
109
+ INSERT INTO worktrees_new (id, work_item_id, branch_name, worktree_path, status, created_at, updated_at)
110
+ SELECT id, work_item_id, branch_name, worktree_path, status, created_at, updated_at
111
+ FROM worktrees
112
+ `, (err) => {
113
+ if (err) return reject(err);
114
+ });
115
+
116
+ db.run('DROP INDEX IF EXISTS idx_worktrees_work_item_id', (err) => {
117
+ if (err) return reject(err);
118
+ });
119
+
120
+ db.run('DROP INDEX IF EXISTS idx_worktrees_status', (err) => {
121
+ if (err) return reject(err);
122
+ });
123
+
124
+ db.run('DROP TABLE worktrees', (err) => {
125
+ if (err) return reject(err);
126
+ });
127
+
128
+ db.run('ALTER TABLE worktrees_new RENAME TO worktrees', (err) => {
129
+ if (err) return reject(err);
130
+ });
131
+
132
+ db.run(`
133
+ CREATE INDEX idx_worktrees_work_item_id
134
+ ON worktrees(work_item_id)
135
+ `, (err) => {
136
+ if (err) return reject(err);
137
+ });
138
+
139
+ db.run(`
140
+ CREATE INDEX idx_worktrees_status
141
+ ON worktrees(status)
142
+ `, (err) => {
143
+ if (err) return reject(err);
144
+ resolve();
145
+ });
146
+ });
147
+ });
148
+ }
149
+ };
@@ -20,11 +20,16 @@ async function runMigrations(db) {
20
20
  });
21
21
  });
22
22
 
23
- // Get list of applied migrations
24
- const applied = await new Promise((resolve, reject) => {
25
- db.all('SELECT id FROM migrations', [], (err, rows) => {
23
+ // Create _meta table for schema versioning
24
+ await new Promise((resolve, reject) => {
25
+ db.run(`
26
+ CREATE TABLE IF NOT EXISTS _meta (
27
+ key TEXT PRIMARY KEY,
28
+ value TEXT
29
+ )
30
+ `, (err) => {
26
31
  if (err) reject(err);
27
- else resolve(rows.map(r => r.id));
32
+ else resolve();
28
33
  });
29
34
  });
30
35
 
@@ -34,6 +39,32 @@ async function runMigrations(db) {
34
39
  .filter(f => f.endsWith('.js') && f !== 'index.js' && !f.endsWith('.test.js'))
35
40
  .sort();
36
41
 
42
+ const knownMigrationCount = files.length;
43
+
44
+ // Check schema version for forward-compatibility
45
+ const currentVersion = await new Promise((resolve, reject) => {
46
+ db.get('SELECT value FROM _meta WHERE key = ?', ['schema_version'], (err, row) => {
47
+ if (err) reject(err);
48
+ else resolve(row ? parseInt(row.value, 10) : 0);
49
+ });
50
+ });
51
+
52
+ if (currentVersion > knownMigrationCount) {
53
+ console.warn(
54
+ `⚠️ Database schema version (${currentVersion}) is newer than this version of JettyPod supports (${knownMigrationCount}).` +
55
+ '\n Please update JettyPod to avoid compatibility issues.'
56
+ );
57
+ return; // Don't run migrations — the DB is from a newer version
58
+ }
59
+
60
+ // Get list of applied migrations
61
+ const applied = await new Promise((resolve, reject) => {
62
+ db.all('SELECT id FROM migrations', [], (err, rows) => {
63
+ if (err) reject(err);
64
+ else resolve(rows.map(r => r.id));
65
+ });
66
+ });
67
+
37
68
  // Run pending migrations
38
69
  for (const file of files) {
39
70
  const migration = require(path.join(migrationsDir, file));
@@ -69,6 +100,18 @@ async function runMigrations(db) {
69
100
  throw err;
70
101
  }
71
102
  }
103
+
104
+ // Update schema version to reflect current state
105
+ await new Promise((resolve, reject) => {
106
+ db.run(
107
+ 'INSERT OR REPLACE INTO _meta (key, value) VALUES (?, ?)',
108
+ ['schema_version', String(knownMigrationCount)],
109
+ (err) => {
110
+ if (err) reject(err);
111
+ else resolve();
112
+ }
113
+ );
114
+ });
72
115
  }
73
116
 
74
117
  module.exports = { runMigrations };
package/lib/schema.js CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  const SCHEMA_SQL = `
13
13
  CREATE TABLE IF NOT EXISTS work_items (
14
- id INTEGER PRIMARY KEY AUTOINCREMENT,
14
+ id INTEGER PRIMARY KEY,
15
15
  type TEXT NOT NULL,
16
16
  title TEXT NOT NULL,
17
17
  description TEXT,
@@ -30,7 +30,9 @@ const SCHEMA_SQL = `
30
30
  scenario_file TEXT,
31
31
  completed_at TEXT,
32
32
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
33
- display_order INTEGER DEFAULT NULL
33
+ display_order INTEGER DEFAULT NULL,
34
+ conversational INTEGER DEFAULT 0,
35
+ plan_at_creation TEXT DEFAULT NULL
34
36
  );
35
37
 
36
38
  CREATE TABLE IF NOT EXISTS project_config (
@@ -40,7 +42,7 @@ const SCHEMA_SQL = `
40
42
  );
41
43
 
42
44
  CREATE TABLE IF NOT EXISTS external_readiness_checklist (
43
- id INTEGER PRIMARY KEY AUTOINCREMENT,
45
+ id INTEGER PRIMARY KEY,
44
46
  category TEXT NOT NULL,
45
47
  item_key TEXT NOT NULL,
46
48
  title TEXT NOT NULL,
@@ -51,7 +53,7 @@ const SCHEMA_SQL = `
51
53
  );
52
54
 
53
55
  CREATE TABLE IF NOT EXISTS discovery_decisions (
54
- id INTEGER PRIMARY KEY AUTOINCREMENT,
56
+ id INTEGER PRIMARY KEY,
55
57
  work_item_id INTEGER NOT NULL,
56
58
  aspect TEXT NOT NULL,
57
59
  decision TEXT NOT NULL,
@@ -61,7 +63,7 @@ const SCHEMA_SQL = `
61
63
  );
62
64
 
63
65
  CREATE TABLE IF NOT EXISTS skill_executions (
64
- id INTEGER PRIMARY KEY AUTOINCREMENT,
66
+ id INTEGER PRIMARY KEY,
65
67
  work_item_id INTEGER NOT NULL,
66
68
  skill_name TEXT NOT NULL,
67
69
  status TEXT DEFAULT 'in_progress',
@@ -73,13 +75,18 @@ const SCHEMA_SQL = `
73
75
  );
74
76
 
75
77
  CREATE TABLE IF NOT EXISTS workflow_gates (
76
- id INTEGER PRIMARY KEY AUTOINCREMENT,
78
+ id INTEGER PRIMARY KEY,
77
79
  work_item_id INTEGER NOT NULL,
78
80
  gate_name TEXT NOT NULL,
79
81
  passed_at DATETIME,
80
82
  UNIQUE(work_item_id, gate_name),
81
83
  FOREIGN KEY (work_item_id) REFERENCES work_items(id)
82
84
  );
85
+
86
+ CREATE TABLE IF NOT EXISTS _meta (
87
+ key TEXT PRIMARY KEY,
88
+ value TEXT
89
+ );
83
90
  `;
84
91
 
85
92
  /**
@@ -7,122 +7,154 @@
7
7
  */
8
8
 
9
9
  const ONBOARDING_EPIC = {
10
- title: 'Project Onboarding',
10
+ title: 'Project Planning',
11
11
  description: 'Get your project set up and planned. Work through these chores one at a time — each one is a short conversation.'
12
12
  };
13
13
 
14
+ const TONE = `HOW TO RESPOND:
15
+ You are a collaborator, not an AI assistant. You're a knowledgeable partner having a real conversation.
16
+ - Do NOT open with a summary or recap of what you've been asked to do
17
+ - Do NOT list steps or outline a plan before starting
18
+ - Do NOT say "I'll help you with...", "Let me guide you through...", or "Great question!"
19
+ - Do NOT use headers, bullet lists, or formatted option blocks in your first message
20
+ - DO jump straight into conversation like a person who just sat down across the table
21
+ - DO ask one question at a time, then actually listen to the response
22
+ - DO keep responses short — a few sentences, not paragraphs
23
+ - DO respond naturally to what the user says, adapting your follow-ups accordingly`;
24
+
14
25
  const ONBOARDING_CHORES = [
15
26
  {
16
27
  title: 'Align on the user journey',
17
- description: `This is the first onboarding chore. Help the user define what their product does.
28
+ description: `${TONE}
29
+
30
+ YOUR ROLE: Help the user articulate what their product does and how people will use it.
18
31
 
19
- CLAUDE SESSION GUIDANCE:
20
- Open with: "What do users DO in this product? Walk me through the flow from opening it to getting value from it."
32
+ CONVERSATION FLOW:
21
33
 
22
- If the user isn't sure, suggest 3 different user journey options:
23
- - Journey 1: [Simple/Direct approach] with flow, pros, cons
24
- - Journey 2: [Balanced approach] with flow, pros, cons
25
- - Journey 3: [Advanced/Guided approach] with flow, pros, cons
34
+ 1. OPEN Jump straight in. Something like:
35
+ "So what are you building? Walk me through what happens when someone opens this thing up."
36
+ (Adapt to context. Be casual. No preamble.)
26
37
 
27
- Ask: "Which journey resonates? Or describe your own."
38
+ 2. LISTEN AND DIG Based on what they say, ask natural follow-ups. One at a time:
39
+ - "And then what? What happens after [thing they mentioned]?"
40
+ - "How do they find that the first time?"
41
+ - "What's the moment where it clicks — like, this is actually useful?"
42
+ Don't rush this. Let them think. Some people need 2-3 exchanges to articulate their vision.
28
43
 
29
- OUTCOME:
30
- - A clear description of the core user journey
31
- - Agreement on the main actions users take
44
+ 3. IF THEY'RE VAGUE — Don't present a formatted options list. Talk through possibilities naturally:
45
+ "I could see this going a few ways. You could do [approach A] really simple, users just [action]. Or something more like [approach B] where they [different flow]. What feels closer?"
46
+ If they're really stuck, describe 2-3 directions conversationally and ask what resonates.
32
47
 
33
- RECORD DECISION:
34
- After the user picks/describes their journey, run:
35
- jettypod work epic-implement <onboarding-epic-id> --aspect="User Journey" --decision="<chosen journey>" --rationale="<why>"
48
+ 4. CONFIRM — Once the journey is clear, reflect it back casually:
49
+ "Cool, so basically: user shows up, [does X], then [does Y], and the payoff is [Z]. That feel right?"
50
+ Wait for them to confirm or adjust.
36
51
 
37
- Then tell the user: "Got it. Close this chat and start the next chore from your backlog to continue."`
52
+ 5. RECORD After they confirm, run:
53
+ jettypod work epic-implement <onboarding-epic-id> --aspect="User Journey" --decision="<summary of chosen journey>" --rationale="<why this flow>"
54
+
55
+ 6. HAND OFF — Say something like: "Nice. Close this chat and start the next chore in your backlog to keep going."`
38
56
  },
39
57
  {
40
58
  title: 'Explore UX approaches',
41
- description: `This is the second onboarding chore. Help the user decide how the product should feel.
59
+ description: `${TONE}
60
+
61
+ YOUR ROLE: Help the user decide how their product should FEEL to use. This is about the experience, not the tech.
42
62
 
43
- CONTEXT FROM PREVIOUS CHORE:
44
- Read the user journey decision first:
63
+ CONTEXT: Read the user journey decision first:
45
64
  jettypod decisions --epic=<onboarding-epic-id>
46
65
 
47
- CLAUDE SESSION GUIDANCE:
48
- Open with: "Based on your user journey: [quote decision]. Now let's figure out how it should feel to use."
66
+ CONVERSATION FLOW:
49
67
 
50
- Present exactly 3 UX approaches (NOT tech stacks focus on the experience):
51
- - Option 1: [Simple approach] — pros, cons, what it feels like
52
- - Option 2: [Balanced approach] pros, cons, what it feels like
53
- - Option 3: [Advanced approach] — pros, cons, what it feels like
68
+ 1. OPEN Reference what they already decided and pivot naturally:
69
+ "So last time you said users would [brief journey recap]. Now I'm curious what should that actually feel like? Like, when someone [key action], are you imagining something minimal and fast, or more guided and hand-holdy?"
70
+ (Use their actual words from the decision. Don't be generic.)
54
71
 
55
- Ask: "Would you like me to create working prototypes of these?"
72
+ 2. EXPLORE THROUGH CONVERSATION Don't dump three formatted options. Talk through directions:
73
+ "One direction would be something really stripped down — [describe the feel]. That works well when [context]. But you could also go more toward [different feel] where [description]. The trade-off is [honest assessment]."
74
+ Let them react. Follow their energy.
56
75
 
57
- If yes, build quick throwaway prototypes using jettypod project prototype commands.
58
- If no, ask which option they prefer.
76
+ 3. GET SPECIFIC Once a direction emerges, push on it:
77
+ "OK so if we go that route, the main screen would probably be [description]. Does that feel right or is that too [much/little]?"
59
78
 
60
- OUTCOME:
61
- - 3 UX options compared
62
- - A winner chosen
63
- - Optionally: working prototypes tested
79
+ 4. OFFER PROTOTYPES (if it would help) — If they're torn or want to see it:
80
+ "Want me to throw together a quick prototype of that? Nothing fancy — just enough to feel it out."
81
+ If yes, use: jettypod project prototype start <approach-name>
82
+ Build a minimal throwaway prototype, then: jettypod project prototype merge
83
+ After they try it: "What did you think? Does that feel like the right direction, or should we adjust?"
64
84
 
65
- RECORD DECISION:
66
- jettypod work epic-implement <onboarding-epic-id> --aspect="UX Approach" --decision="<chosen approach>" --rationale="<why>"
85
+ 5. CONFIRM — Lock in the winner:
86
+ "Alright, so the feel is [description]. I'll record that."
67
87
 
68
- Then tell the user: "Close this chat and start the next chore from your backlog."`
88
+ 6. RECORD Run:
89
+ jettypod work epic-implement <onboarding-epic-id> --aspect="UX Approach" --decision="<chosen approach>" --rationale="<why>"
90
+
91
+ 7. HAND OFF — "Close this chat and start the next chore from your backlog."`
69
92
  },
70
93
  {
71
94
  title: 'Choose a tech stack',
72
- description: `This is the third onboarding chore. Help the user pick the right tech stack.
95
+ description: `${TONE}
96
+
97
+ YOUR ROLE: Help the user pick the right tech stack based on what they're building and how it should feel.
73
98
 
74
- CONTEXT FROM PREVIOUS CHORES:
75
- Read previous decisions first:
99
+ CONTEXT: Read previous decisions first:
76
100
  jettypod decisions --epic=<onboarding-epic-id>
77
101
 
78
- CLAUDE SESSION GUIDANCE:
79
- Open with: "You're building [journey] with a [UX approach] experience. Let's pick the tech stack."
102
+ CONVERSATION FLOW:
80
103
 
81
- Present exactly 3 tech stack options appropriate for their UX approach:
82
- - Option 1: [Stack name] pros, cons, what development will feel like
83
- - Option 2: [Stack name] — pros, cons, what development will feel like
84
- - Option 3: [Stack name] pros, cons, what development will feel like
104
+ 1. OPEN Connect the dots from previous decisions:
105
+ "You're building [journey] and you want it to feel [UX approach]. That actually narrows down the tech quite a bit."
106
+ Then lead with your honest take:
107
+ "I'd probably go with [recommendation] for this. Here's why [reason]."
108
+ (Have an opinion. Don't just present options neutrally.)
85
109
 
86
- Include "Other options considered" with brief reasons for not recommending.
110
+ 2. HAVE A REAL DISCUSSION After giving your take, open it up:
111
+ "That said — do you have a preference? Are you already comfortable with something, or is there a stack you've been wanting to try?"
112
+ Respond to what they say. If they push back, engage with it honestly:
113
+ "Yeah, [their preference] could work. The main thing you'd lose is [trade-off]. The main thing you'd gain is [benefit]. Honestly, either would be fine for this."
87
114
 
88
- OUTCOME:
89
- - 3 tech stack options compared
90
- - A winner chosen with rationale
115
+ 3. IF THEY WANT OPTIONS — Talk through 2-3 stacks conversationally, not as formatted comparison blocks:
116
+ "[Stack A] would be the fastest to get going — you'd have [benefit] out of the box. [Stack B] is more flexible but you'd need to wire up [thing] yourself. And then there's [Stack C] which is honestly overkill here unless you specifically want [thing]."
91
117
 
92
- RECORD DECISION:
93
- jettypod work epic-implement <onboarding-epic-id> --aspect="Tech Stack" --decision="<chosen stack>" --rationale="<why>"
118
+ 4. LAND ON A DECISION — Once they choose:
119
+ "Solid choice. [One sentence of genuine validation why it fits their specific project, not generic praise]."
94
120
 
95
- Then tell the user: "Close this chat and start the last onboarding chore."`
121
+ 5. RECORD Run:
122
+ jettypod work epic-implement <onboarding-epic-id> --aspect="Tech Stack" --decision="<chosen stack>" --rationale="<why>"
123
+
124
+ 6. HAND OFF — "One more chore left — close this chat and start it from your backlog."`
96
125
  },
97
126
  {
98
127
  title: 'Break the project into epics',
99
- description: `This is the final onboarding chore. Break the project into buildable phases.
128
+ description: `${TONE}
129
+
130
+ YOUR ROLE: Break the project into buildable phases (epics) based on everything they've decided.
100
131
 
101
- CONTEXT FROM PREVIOUS CHORES:
102
- Read all previous decisions first:
132
+ CONTEXT: Read all previous decisions first:
103
133
  jettypod decisions --epic=<onboarding-epic-id>
104
134
 
105
- CLAUDE SESSION GUIDANCE:
106
- Open with: "You're building [journey] as a [UX approach] experience using [tech stack]. Let's break this into phases."
135
+ CONVERSATION FLOW:
107
136
 
108
- Explain: "Epics are phase-level chunks of work. Each epic contains features things users can actually do."
137
+ 1. OPEN Bring it all together and jump straight to the breakdown:
138
+ "Alright — you're building [journey], it should feel [UX approach], and you're using [tech stack]. Let me suggest how to break this into phases."
139
+ Then just propose the epics conversationally:
140
+ "I'd start with [Epic 1] — that's the foundation, stuff like [examples]. Then [Epic 2] which covers [what]. And then [Epic 3] for [what]."
141
+ (Don't over-explain what an epic is. Keep it natural.)
109
142
 
110
- Propose 3-5 epics based on everything they've decided:
111
- - Epic 1: [Name]what it covers
112
- - Epic 2: [Name] — what it covers
113
- - Epic 3: [Name] — what it covers
143
+ 2. QUICK CONTEXT (only if needed) — If they seem unsure about the structure:
144
+ "Each of these is a phase. Inside each one we'll define specific features things users can actually do. You don't need to think about that yet though."
114
145
 
115
- Ask: "Sound right? What would you add or change?"
146
+ 3. GET FEEDBACK After proposing:
147
+ "Does that breakdown make sense? Anything you'd add, cut, or reorder?"
148
+ Adjust based on their input. Don't be precious about your proposal.
116
149
 
117
- After confirmation, create each epic:
118
- jettypod work create epic "<title>" "<description>"
150
+ 4. CREATE — Once they confirm, create each epic:
151
+ jettypod work create epic "<title>" "<description>"
152
+ Do this for each one.
119
153
 
120
- OUTCOME:
121
- - 3-5 epics created in the backlog
122
- - A recommendation for which epic to start first
154
+ 5. RECOMMEND A STARTING POINT:
155
+ "If I were you, I'd start with [Epic name] — [brief reason, like 'everything else depends on it' or 'it's the quickest win to get something real']."
123
156
 
124
- CLOSING:
125
- Tell the user: "Your project is planned! Pick an epic from the backlog and tell Claude 'Let's plan [epic name]' to start building."`
157
+ 6. CLOSE — "Your project is planned. Pick an epic from the backlog and tell Claude 'Let's plan [epic name]' to start building."`
126
158
  }
127
159
  ];
128
160