← Back to Kontasks
Phase 4 Detection Logic - Code Review
Proposed detection logic for determining if a user is new
Output
🔍 New User Detection Logic
Current State (session-briefing.ts:326-343)
function buildBriefingCard(recentKontasks, incompleteKontasks, sessionContext, statusLineStats) { // Filter out progress kontasks and bad titles const filteredIncomplete = incompleteKontasks.filter(function(k) { if (k.type === 'progress') return false; return cleanTitle(k.title) !== null; }); const filteredRecent = recentKontasks.filter(function(k) { if (k.type === 'progress') return false; return cleanTitle(k.title) !== null; }); const hasRecent = filteredRecent.length > 0; const hasIncomplete = filteredIncomplete.length > 0; const hasContext = sessionContext && (sessionContext.recommendations?.length > 0 || sessionContext.vision); const hasStats = statusLineStats && statusLineStats.sessionCount > 0; // Current "empty state" - just shows generic message if (!hasRecent && !hasIncomplete && !hasContext && !hasStats) { return '<div ...>📋 No recent activity. Ready for a fresh start!</div>'; } // ... rest of briefing card }
📋 Proposed Detection Logic
/** * Determine if user should see onboarding vs regular briefing * * Criteria for "new user": * 1. No kontasks at all (not just no recent/incomplete) * 2. No saved briefing state in localStorage * 3. sessionContext.isNewUser flag from server */ function isNewUser(recentKontasks, incompleteKontasks, sessionContext) { // Check 1: Server-side flag (most reliable) if (sessionContext && sessionContext.isNewUser === true) { return true; } // Check 2: No kontask history at all const totalKontasks = (recentKontasks?.length || 0) + (incompleteKontasks?.length || 0); if (totalKontasks === 0) { // Double-check localStorage for any previous session const savedBriefing = localStorage.getItem('konui_session_briefing'); const hasHistory = localStorage.getItem('konui_console_history'); if (!savedBriefing && !hasHistory) { return true; // Truly new user } } return false; }
🖥️ Server-Side Enhancement (session-context.ts)
// In getSessionContextSummary() - add isNewUser flag export async function getSessionContextSummary( recentKontasks?: Array<{ title: string; scope?: string; tags?: string[] }>, userKontaskCount?: number // NEW: total kontasks for this user ): Promise<SessionContextSummary> { const context = await getSessionContext(recentKontasks); return { ...existingFields, isNewUser: userKontaskCount === 0, // NEW }; }
🔄 Router Enhancement (router.ts:587-602)
// Session context API - add user kontask count if (path === "/api/session-context" && method === "GET") { const { getSessionContextSummary } = await import("./session-context.ts"); // Get recent completed kontasks for context-aware recommendations const recentTasks = kontaskStore.getKontasksByStatus("completed") .slice(0, 10); // NEW: Count total kontasks for this user const userKontaskCount = kontaskStore.getKontasksByUser(username).length; const summary = await getSessionContextSummary( recentKontasks, userKontaskCount // Pass to function ); return jsonResponse(summary); }
✅ Detection Criteria Summary
| Check | Source | Weight |
|---|---|---|
sessionContext.isNewUser |
Server (kontask DB) | Primary - Most reliable |
| Zero kontasks in API response | Client (API data) | Secondary - Backup check |
| No localStorage history | Client (browser) | Tertiary - Edge cases only |
⚠️ Edge Cases
- Cleared localStorage: User clears browser data → Server flag still works
- New device: Same user, new browser → Server knows they're not new
- Admin role: Admins see all kontasks - need to filter by
createdBy - First kontask in progress: Show onboarding until first kontask is completed
What's Next?
Review the logic and choose an action:
Quick Actions
Original Request
No layout configured
Details
Type
General
Status
Completed
Scope
vibetools
Tags
kontasksuionboarding
Created
4 Jan 2026, 3:55 pm
Updated
4 Jan 2026, 3:55 pm
Timing
⏱️ 81.7s
1 tools
● TTFE 3%
● Thinking 96%
● Tools 0%
Created By
claude
Raw Data
{
"id": "aea1ff89-d1c7-4b9a-bdb7-dac153a395f4",
"type": "general",
"status": "completed",
"title": "Phase 4 Detection Logic - Code Review",
"description": "Proposed detection logic for determining if a user is new",
"context": {
"output": "<div style=\"background:#1e1e1e;color:#e0e0e0;padding:20px;border-radius:8px;font-family:sans-serif;\">\n<h2 style=\"color:#fff;margin:0 0 16px 0;\">🔍 New User Detection Logic</h2>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"margin:0 0 12px 0;color:#98c379;\">Current State (session-briefing.ts:326-343)</h3>\n<pre style=\"background:#1a1a2e;padding:12px;border-radius:6px;color:#e0e0e0;font-size:0.85rem;overflow-x:auto;line-height:1.6;\"><span style=\"color:#c678dd;\">function</span> <span style=\"color:#61afef;\">buildBriefingCard</span>(recentKontasks, incompleteKontasks, sessionContext, statusLineStats) {\n <span style=\"color:#7f848e;\">// Filter out progress kontasks and bad titles</span>\n <span style=\"color:#c678dd;\">const</span> filteredIncomplete = incompleteKontasks.<span style=\"color:#61afef;\">filter</span>(<span style=\"color:#c678dd;\">function</span>(k) {\n <span style=\"color:#c678dd;\">if</span> (k.type === <span style=\"color:#98c379;\">'progress'</span>) <span style=\"color:#c678dd;\">return</span> <span style=\"color:#d19a66;\">false</span>;\n <span style=\"color:#c678dd;\">return</span> <span style=\"color:#61afef;\">cleanTitle</span>(k.title) !== <span style=\"color:#d19a66;\">null</span>;\n });\n <span style=\"color:#c678dd;\">const</span> filteredRecent = recentKontasks.<span style=\"color:#61afef;\">filter</span>(<span style=\"color:#c678dd;\">function</span>(k) {\n <span style=\"color:#c678dd;\">if</span> (k.type === <span style=\"color:#98c379;\">'progress'</span>) <span style=\"color:#c678dd;\">return</span> <span style=\"color:#d19a66;\">false</span>;\n <span style=\"color:#c678dd;\">return</span> <span style=\"color:#61afef;\">cleanTitle</span>(k.title) !== <span style=\"color:#d19a66;\">null</span>;\n });\n\n <span style=\"color:#c678dd;\">const</span> hasRecent = filteredRecent.length > <span style=\"color:#d19a66;\">0</span>;\n <span style=\"color:#c678dd;\">const</span> hasIncomplete = filteredIncomplete.length > <span style=\"color:#d19a66;\">0</span>;\n <span style=\"color:#c678dd;\">const</span> hasContext = sessionContext && (sessionContext.recommendations?.length > <span style=\"color:#d19a66;\">0</span> || sessionContext.vision);\n <span style=\"color:#c678dd;\">const</span> hasStats = statusLineStats && statusLineStats.sessionCount > <span style=\"color:#d19a66;\">0</span>;\n\n <span style=\"color:#7f848e;\">// Current \"empty state\" - just shows generic message</span>\n <span style=\"color:#c678dd;\">if</span> (!hasRecent && !hasIncomplete && !hasContext && !hasStats) {\n <span style=\"color:#c678dd;\">return</span> <span style=\"color:#98c379;\">'<div ...>📋 No recent activity. Ready for a fresh start!</div>'</span>;\n }\n <span style=\"color:#7f848e;\">// ... rest of briefing card</span>\n}</pre>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"margin:0 0 12px 0;color:#61afef;\">📋 Proposed Detection Logic</h3>\n<pre style=\"background:#1a1a2e;padding:12px;border-radius:6px;color:#e0e0e0;font-size:0.85rem;overflow-x:auto;line-height:1.6;\"><span style=\"color:#7f848e;\">/**\n * Determine if user should see onboarding vs regular briefing\n * \n * Criteria for \"new user\":\n * 1. No kontasks at all (not just no recent/incomplete)\n * 2. No saved briefing state in localStorage\n * 3. sessionContext.isNewUser flag from server\n */</span>\n<span style=\"color:#c678dd;\">function</span> <span style=\"color:#61afef;\">isNewUser</span>(recentKontasks, incompleteKontasks, sessionContext) {\n <span style=\"color:#7f848e;\">// Check 1: Server-side flag (most reliable)</span>\n <span style=\"color:#c678dd;\">if</span> (sessionContext && sessionContext.isNewUser === <span style=\"color:#d19a66;\">true</span>) {\n <span style=\"color:#c678dd;\">return</span> <span style=\"color:#d19a66;\">true</span>;\n }\n \n <span style=\"color:#7f848e;\">// Check 2: No kontask history at all</span>\n <span style=\"color:#c678dd;\">const</span> totalKontasks = (recentKontasks?.length || <span style=\"color:#d19a66;\">0</span>) + (incompleteKontasks?.length || <span style=\"color:#d19a66;\">0</span>);\n <span style=\"color:#c678dd;\">if</span> (totalKontasks === <span style=\"color:#d19a66;\">0</span>) {\n <span style=\"color:#7f848e;\">// Double-check localStorage for any previous session</span>\n <span style=\"color:#c678dd;\">const</span> savedBriefing = localStorage.<span style=\"color:#61afef;\">getItem</span>(<span style=\"color:#98c379;\">'konui_session_briefing'</span>);\n <span style=\"color:#c678dd;\">const</span> hasHistory = localStorage.<span style=\"color:#61afef;\">getItem</span>(<span style=\"color:#98c379;\">'konui_console_history'</span>);\n \n <span style=\"color:#c678dd;\">if</span> (!savedBriefing && !hasHistory) {\n <span style=\"color:#c678dd;\">return</span> <span style=\"color:#d19a66;\">true</span>; <span style=\"color:#7f848e;\">// Truly new user</span>\n }\n }\n \n <span style=\"color:#c678dd;\">return</span> <span style=\"color:#d19a66;\">false</span>;\n}</pre>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"margin:0 0 12px 0;color:#c678dd;\">🖥️ Server-Side Enhancement (session-context.ts)</h3>\n<pre style=\"background:#1a1a2e;padding:12px;border-radius:6px;color:#e0e0e0;font-size:0.85rem;overflow-x:auto;line-height:1.6;\"><span style=\"color:#7f848e;\">// In getSessionContextSummary() - add isNewUser flag</span>\n<span style=\"color:#c678dd;\">export async function</span> <span style=\"color:#61afef;\">getSessionContextSummary</span>(\n recentKontasks?: Array<{ title: string; scope?: string; tags?: string[] }>,\n <span style=\"color:#e5c07b;\">userKontaskCount?: number</span> <span style=\"color:#7f848e;\">// NEW: total kontasks for this user</span>\n): Promise<SessionContextSummary> {\n <span style=\"color:#c678dd;\">const</span> context = <span style=\"color:#c678dd;\">await</span> <span style=\"color:#61afef;\">getSessionContext</span>(recentKontasks);\n\n <span style=\"color:#c678dd;\">return</span> {\n ...existingFields,\n <span style=\"color:#e5c07b;\">isNewUser</span>: userKontaskCount === <span style=\"color:#d19a66;\">0</span>, <span style=\"color:#7f848e;\">// NEW</span>\n };\n}</pre>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"margin:0 0 12px 0;color:#f59e0b;\">🔄 Router Enhancement (router.ts:587-602)</h3>\n<pre style=\"background:#1a1a2e;padding:12px;border-radius:6px;color:#e0e0e0;font-size:0.85rem;overflow-x:auto;line-height:1.6;\"><span style=\"color:#7f848e;\">// Session context API - add user kontask count</span>\n<span style=\"color:#c678dd;\">if</span> (path === <span style=\"color:#98c379;\">\"/api/session-context\"</span> && method === <span style=\"color:#98c379;\">\"GET\"</span>) {\n <span style=\"color:#c678dd;\">const</span> { getSessionContextSummary } = <span style=\"color:#c678dd;\">await</span> <span style=\"color:#61afef;\">import</span>(<span style=\"color:#98c379;\">\"./session-context.ts\"</span>);\n\n <span style=\"color:#7f848e;\">// Get recent completed kontasks for context-aware recommendations</span>\n <span style=\"color:#c678dd;\">const</span> recentTasks = kontaskStore.<span style=\"color:#61afef;\">getKontasksByStatus</span>(<span style=\"color:#98c379;\">\"completed\"</span>)\n .<span style=\"color:#61afef;\">slice</span>(<span style=\"color:#d19a66;\">0</span>, <span style=\"color:#d19a66;\">10</span>);\n\n <span style=\"color:#7f848e;\">// NEW: Count total kontasks for this user</span>\n <span style=\"color:#c678dd;\">const</span> <span style=\"color:#e5c07b;\">userKontaskCount</span> = kontaskStore.<span style=\"color:#61afef;\">getKontasksByUser</span>(username).length;\n\n <span style=\"color:#c678dd;\">const</span> summary = <span style=\"color:#c678dd;\">await</span> <span style=\"color:#61afef;\">getSessionContextSummary</span>(\n recentKontasks,\n <span style=\"color:#e5c07b;\">userKontaskCount</span> <span style=\"color:#7f848e;\">// Pass to function</span>\n );\n <span style=\"color:#c678dd;\">return</span> <span style=\"color:#61afef;\">jsonResponse</span>(summary);\n}</pre>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"margin:0 0 12px 0;color:#22c55e;\">✅ Detection Criteria Summary</h3>\n<table style=\"width:100%;color:#e0e0e0;border-collapse:collapse;font-size:0.9rem;\">\n<tr style=\"border-bottom:1px solid #444;\">\n<th style=\"text-align:left;padding:8px;color:#fff;\">Check</th>\n<th style=\"text-align:left;padding:8px;color:#fff;\">Source</th>\n<th style=\"text-align:left;padding:8px;color:#fff;\">Weight</th>\n</tr>\n<tr style=\"border-bottom:1px solid #333;\">\n<td style=\"padding:8px;\"><code>sessionContext.isNewUser</code></td>\n<td style=\"padding:8px;\">Server (kontask DB)</td>\n<td style=\"padding:8px;\"><span style=\"color:#22c55e;\">Primary</span> - Most reliable</td>\n</tr>\n<tr style=\"border-bottom:1px solid #333;\">\n<td style=\"padding:8px;\">Zero kontasks in API response</td>\n<td style=\"padding:8px;\">Client (API data)</td>\n<td style=\"padding:8px;\"><span style=\"color:#eab308;\">Secondary</span> - Backup check</td>\n</tr>\n<tr>\n<td style=\"padding:8px;\">No localStorage history</td>\n<td style=\"padding:8px;\">Client (browser)</td>\n<td style=\"padding:8px;\"><span style=\"color:#7f848e;\">Tertiary</span> - Edge cases only</td>\n</tr>\n</table>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"margin:0 0 12px 0;color:#ef4444;\">⚠️ Edge Cases</h3>\n<ul style=\"color:#e0e0e0;margin:0;padding-left:20px;line-height:1.8;\">\n<li><strong>Cleared localStorage:</strong> User clears browser data → Server flag still works</li>\n<li><strong>New device:</strong> Same user, new browser → Server knows they're not new</li>\n<li><strong>Admin role:</strong> Admins see all kontasks - need to filter by <code>createdBy</code></li>\n<li><strong>First kontask in progress:</strong> Show onboarding until first kontask is <em>completed</em></li>\n</ul>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;\">\n<h4 style=\"margin:0 0 8px 0;color:#fff;\">What's Next?</h4>\n<p style=\"color:#9ca3af;margin:0;\">Review the logic and choose an action:</p>\n</div>\n</div>",
"requestedAt": "2026-01-04T05:48:00.000Z",
"requestId": "3ab884cd-0a42-4635-9465-1a76e2046d13",
"choices": [
{
"label": "Approve & implement",
"value": "This detection logic looks good - proceed with implementing Phase 4 using this approach",
"primary": true
},
{
"label": "Modify criteria",
"value": "I want to modify the detection criteria - let me explain what changes I'd like"
},
{
"label": "Show onboarding UI",
"value": "Show me the proposed onboarding card UI code before implementing"
}
],
"turnTiming": {
"totalMs": 81678,
"ttfeMs": 2815,
"thinkingMs": 78533,
"toolExecutionMs": 329,
"toolCallCount": 1,
"thinkingPct": 96,
"toolsPct": 0,
"ttfePct": 3
}
},
"createdBy": "claude",
"createdAt": "2026-01-04T05:55:26.348Z",
"updatedAt": "2026-01-04T05:55:32.753Z",
"requestId": "3ab884cd-0a42-4635-9465-1a76e2046d13",
"scope": "vibetools",
"tags": [
"kontasks",
"ui",
"onboarding"
],
"targetUser": "claude"
}