Completed
on 7 Jan 2026, 8:12 am

Output

🔧 Kontask Technical Architecture

1. Yes, Same Turn - MCP Tool Call

Kontasks are created within the same Claude turn via an MCP (Model Context Protocol) tool call. When I call konui_create_task, it's a synchronous tool invocation that:

  1. Sends JSON payload to konui's MCP server (port 8666)
  2. konui writes to /konnectvol/konui/data/kontasks.jsonl
  3. Returns success response to Claude
  4. Claude continues (or ends) the turn

2. The Flow Diagram

User prompt
    │
    ▼
konsole (spawns Claude CLI subprocess)
    │
    ▼
Claude processes, calls MCP tool:
    │   konui_create_task({...})
    │
    ▼
konui MCP server receives tool call
    │
    ├──▶ Writes to kontasks.jsonl
    │
    └──▶ Returns {success: true, task: {...}}
    │
    ▼
Claude receives response, turn continues/ends
    │
    ▼
Dashboard polls/renders kontask card

3. Why Not Just Plain Text?

ReasonPlain TextKontask Card
Rich Formatting❌ Monospace only✅ Full HTML/CSS
Images❌ Can't display✅ <img> tags work
Persistence❌ Lost on refresh✅ Stored in JSONL
Recovery❌ Stream dies = lost✅ requestId links back
Interactivity❌ Read-only✅ Clickable choices
Async Decisions❌ Must respond now✅ Approve later

4. The Console Text vs Card Trade-off

When I write text after a tool call, it shows in the console stream but is NOT saved to the kontask. This is by design:

  • Console text = ephemeral, streaming output
  • Kontask card = persistent, structured artifact

That's why CLAUDE.md instructs: "Include ALL content inside context.output HTML"

5. Recovery Mechanism

The requestId in each kontask enables recovery:

// Dashboard generates UUID for each prompt
requestId: "7a8feb4b-a8a3-4995-9476-b6f12e3b915d"

// If SSE stream dies mid-turn:
1. Dashboard polls kontasks.jsonl
2. Finds kontask with matching requestId
3. Renders the card (even though stream died)

Summary

Kontasks are MCP tool calls within the same turn that create persistent, rich HTML artifacts. They solve the fundamental limitations of streaming text: no images, no persistence, no async interaction. The trade-off is that anything written outside context.output is console-only.

Quick Actions

Original Request

No layout configured

Details

Type General
Status Completed
Scope vibetools
Tags kontasksarchitectureconsole
Created 7 Jan 2026, 8:12 am
Updated 7 Jan 2026, 8:12 am
Timing
⏱️ 39.5s
0 tools
TTFE 0% Thinking 100% Tools 0%
Created By claude

Raw Data

{
  "id": "e0dfcac9-8743-4f29-a23a-1cbf59aafbba",
  "type": "general",
  "status": "completed",
  "title": "Kontask Technical Architecture Explained",
  "description": "Deep dive into how kontask cards are generated and why they exist",
  "context": {
    "output": "<div style=\"background:#1e1e1e;color:#e0e0e0;padding:20px;border-radius:8px;font-family:sans-serif;\"><h2 style=\"color:#fff;margin:0 0 20px 0;\">🔧 Kontask Technical Architecture</h2><div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\"><h3 style=\"margin:0 0 12px 0;color:#61afef;\">1. Yes, Same Turn - MCP Tool Call</h3><p style=\"color:#e0e0e0;line-height:1.7;margin:0;\">Kontasks are created <strong>within the same Claude turn</strong> via an MCP (Model Context Protocol) tool call. When I call <code style=\"background:#3d3d3d;padding:2px 6px;border-radius:3px;color:#e5c07b;\">konui_create_task</code>, it's a synchronous tool invocation that:</p><ol style=\"color:#e0e0e0;line-height:1.8;margin:12px 0 0 0;padding-left:24px;\"><li>Sends JSON payload to konui's MCP server (port 8666)</li><li>konui writes to <code style=\"background:#3d3d3d;padding:2px 6px;border-radius:3px;color:#98c379;\">/konnectvol/konui/data/kontasks.jsonl</code></li><li>Returns success response to Claude</li><li>Claude continues (or ends) the turn</li></ol></div><div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\"><h3 style=\"margin:0 0 12px 0;color:#61afef;\">2. The Flow Diagram</h3><pre style=\"background:#1a1a1a;padding:16px;border-radius:6px;overflow-x:auto;color:#e0e0e0;font-family:'Consolas','Monaco',monospace;font-size:0.9em;line-height:1.6;\"><span style=\"color:#7f848e;\">User prompt</span>\n    │\n    ▼\n<span style=\"color:#c678dd;\">konsole</span> (spawns Claude CLI subprocess)\n    │\n    ▼\n<span style=\"color:#98c379;\">Claude</span> processes, calls MCP tool:\n    │   <span style=\"color:#e5c07b;\">konui_create_task({...})</span>\n    │\n    ▼\n<span style=\"color:#61afef;\">konui MCP server</span> receives tool call\n    │\n    ├──▶ Writes to kontasks.jsonl\n    │\n    └──▶ Returns <span style=\"color:#98c379;\">{success: true, task: {...}}</span>\n    │\n    ▼\n<span style=\"color:#98c379;\">Claude</span> receives response, turn continues/ends\n    │\n    ▼\n<span style=\"color:#c678dd;\">Dashboard</span> polls/renders kontask card</pre></div><div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\"><h3 style=\"margin:0 0 12px 0;color:#61afef;\">3. Why Not Just Plain Text?</h3><table style=\"width:100%;border-collapse:collapse;margin-top:8px;\"><tr style=\"border-bottom:1px solid #3d3d3d;\"><th style=\"text-align:left;padding:10px;color:#7f848e;\">Reason</th><th style=\"text-align:left;padding:10px;color:#7f848e;\">Plain Text</th><th style=\"text-align:left;padding:10px;color:#7f848e;\">Kontask Card</th></tr><tr style=\"border-bottom:1px solid #3d3d3d;\"><td style=\"padding:10px;color:#e5c07b;\">Rich Formatting</td><td style=\"padding:10px;color:#ef4444;\">❌ Monospace only</td><td style=\"padding:10px;color:#22c55e;\">✅ Full HTML/CSS</td></tr><tr style=\"border-bottom:1px solid #3d3d3d;\"><td style=\"padding:10px;color:#e5c07b;\">Images</td><td style=\"padding:10px;color:#ef4444;\">❌ Can't display</td><td style=\"padding:10px;color:#22c55e;\">✅ &lt;img&gt; tags work</td></tr><tr style=\"border-bottom:1px solid #3d3d3d;\"><td style=\"padding:10px;color:#e5c07b;\">Persistence</td><td style=\"padding:10px;color:#ef4444;\">❌ Lost on refresh</td><td style=\"padding:10px;color:#22c55e;\">✅ Stored in JSONL</td></tr><tr style=\"border-bottom:1px solid #3d3d3d;\"><td style=\"padding:10px;color:#e5c07b;\">Recovery</td><td style=\"padding:10px;color:#ef4444;\">❌ Stream dies = lost</td><td style=\"padding:10px;color:#22c55e;\">✅ requestId links back</td></tr><tr style=\"border-bottom:1px solid #3d3d3d;\"><td style=\"padding:10px;color:#e5c07b;\">Interactivity</td><td style=\"padding:10px;color:#ef4444;\">❌ Read-only</td><td style=\"padding:10px;color:#22c55e;\">✅ Clickable choices</td></tr><tr><td style=\"padding:10px;color:#e5c07b;\">Async Decisions</td><td style=\"padding:10px;color:#ef4444;\">❌ Must respond now</td><td style=\"padding:10px;color:#22c55e;\">✅ Approve later</td></tr></table></div><div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\"><h3 style=\"margin:0 0 12px 0;color:#61afef;\">4. The Console Text vs Card Trade-off</h3><p style=\"color:#e0e0e0;line-height:1.7;margin:0 0 12px 0;\">When I write text after a tool call, it shows in the <strong>console stream</strong> but is <strong>NOT saved</strong> to the kontask. This is by design:</p><ul style=\"color:#e0e0e0;line-height:1.8;margin:0;padding-left:24px;\"><li><span style=\"color:#61afef;\">Console text</span> = ephemeral, streaming output</li><li><span style=\"color:#98c379;\">Kontask card</span> = persistent, structured artifact</li></ul><p style=\"color:#9ca3af;margin:12px 0 0 0;font-style:italic;\">That's why CLAUDE.md instructs: \"Include ALL content inside context.output HTML\"</p></div><div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\"><h3 style=\"margin:0 0 12px 0;color:#61afef;\">5. Recovery Mechanism</h3><p style=\"color:#e0e0e0;line-height:1.7;margin:0;\">The <code style=\"background:#3d3d3d;padding:2px 6px;border-radius:3px;color:#e5c07b;\">requestId</code> in each kontask enables recovery:</p><pre style=\"background:#1a1a1a;padding:12px;border-radius:6px;margin-top:12px;color:#e0e0e0;font-family:'Consolas','Monaco',monospace;font-size:0.85em;\"><span style=\"color:#7f848e;\">// Dashboard generates UUID for each prompt</span>\nrequestId: <span style=\"color:#98c379;\">\"7a8feb4b-a8a3-4995-9476-b6f12e3b915d\"</span>\n\n<span style=\"color:#7f848e;\">// If SSE stream dies mid-turn:</span>\n1. Dashboard polls kontasks.jsonl\n2. Finds kontask with matching requestId\n3. Renders the card (even though stream died)</pre></div><div style=\"background:#2d2d2d;padding:16px;border-radius:6px;\"><h4 style=\"margin:0 0 8px 0;color:#fff;\">Summary</h4><p style=\"color:#9ca3af;margin:0;line-height:1.7;\">Kontasks are MCP tool calls within the same turn that create <strong>persistent, rich HTML artifacts</strong>. They solve the fundamental limitations of streaming text: no images, no persistence, no async interaction. The trade-off is that anything written outside <code style=\"background:#3d3d3d;padding:2px 6px;border-radius:3px;\">context.output</code> is console-only.</p></div></div>",
    "requestedAt": "2026-01-07T02:24:00.000Z",
    "requestId": "7a8feb4b-a8a3-4995-9476-b6f12e3b915d",
    "choices": [
      {
        "label": "Show JSONL format",
        "value": "Show me what a kontask looks like in the raw kontasks.jsonl file",
        "primary": true
      },
      {
        "label": "Explain MCP",
        "value": "Explain how MCP (Model Context Protocol) works in more detail"
      },
      {
        "label": "Show recovery flow",
        "value": "Walk me through the kontask recovery flow when SSE disconnects"
      }
    ],
    "turnTiming": {
      "totalMs": 39541,
      "ttfeMs": 53,
      "thinkingMs": 39488,
      "toolExecutionMs": 0,
      "toolCallCount": 0,
      "thinkingPct": 100,
      "toolsPct": 0,
      "ttfePct": 0
    }
  },
  "createdBy": "claude",
  "createdAt": "2026-01-06T22:12:05.136Z",
  "updatedAt": "2026-01-06T22:12:10.251Z",
  "requestId": "7a8feb4b-a8a3-4995-9476-b6f12e3b915d",
  "scope": "vibetools",
  "tags": [
    "kontasks",
    "architecture",
    "console"
  ],
  "targetUser": "claude"
}
DashboardReportsKontasksSessionsTelemetryLogs + Go