Completed
on 4 Jan 2026, 3:55 pm

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;\">'&lt;div ...&gt;📋 No recent activity. Ready for a fresh start!&lt;/div&gt;'</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&lt;{ title: string; scope?: string; tags?: string[] }&gt;,\n  <span style=\"color:#e5c07b;\">userKontaskCount?: number</span>  <span style=\"color:#7f848e;\">// NEW: total kontasks for this user</span>\n): Promise&lt;SessionContextSummary&gt; {\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"
}
DashboardReportsKontasksSessionsTelemetryLogs + Go