Completed
on 2 Jan 2026, 3:10 pm

Output

Warm Session Cache Design

Integrating process caching with konsole's existing --resume mechanism

Current Architecture (2 Layers)

Layer 1: Konsole Session
session.tsses_abc123 (persisted to disk, 24hr TTL)
           → stores claudeSessionId for resume
           → tracks kontexts, status, working history

Layer 2: Claude Process
claude.tsspawnClaude() called PER PROMPT
          → spawns: claude --print --resume {claudeSessionId} "prompt"
          → process exits after each response
          → ~1-3 seconds startup overhead

Key Insight: --resume ≠ Process Reuse

Currently --resume passes the Claude session ID to a new process. The new process loads conversation history from Claude's internal storage (~/.claude/), but still pays the full startup cost.

Prompt 1: claude --print "Hello"          → spawn, run, exit (3s)
Prompt 2: claude --print --resume abc "Hi" → spawn, load, run, exit (3s)
Prompt 3: claude --print --resume abc "Bye" → spawn, load, run, exit (3s)
                                            Total: 9s overhead

Warm Cache: Keep Process Alive

Instead of exiting after each response, keep the Claude process running and pipe new prompts via stdin.

Prompt 1: claude --print "Hello"          → spawn (3s) + run
Prompt 2: (stdin) "Hi"                    → immediate (0s)
Prompt 3: (stdin) "Bye"                   → immediate (0s)
[5 min idle] → kill process
Prompt 4: claude --print --resume abc     → spawn (3s) + run
                                            Total: 6s overhead (vs 12s)

Implementation Changes

1. claude.ts - Process Pool

// NEW: Track warm processes
const warmProcesses = new Map<string, WarmClaudeProcess>();

interface WarmClaudeProcess {
  process: Deno.ChildProcess;
  stdin: WritableStreamDefaultWriter;
  lastUsedAt: number;
  claudeSessionId: string;
}

// Reuse or spawn
function getOrSpawnClaude(sessionId, prompt, claudeSessionId) {
  const warm = warmProcesses.get(sessionId);
  if (warm && warm.process.running) {
    warm.lastUsedAt = Date.now();
    warm.stdin.write(prompt); // Send via stdin
    return warm;
  }
  // Cold start - spawn new
  return spawnWarmClaude(sessionId, prompt, claudeSessionId);
}

2. Idle Timeout (5 min)

// Run every 60 seconds
setInterval(() => {
  const now = Date.now();
  for (const [id, warm] of warmProcesses) {
    if (now - warm.lastUsedAt > 5 * 60 * 1000) {
      warm.process.kill("SIGTERM");
      warmProcesses.delete(id);
      log.info("Expired warm process", { sessionId: id });
    }
  }
}, 60_000);

3. Fallback to --resume

// When warm process expires, fall back to --resume
if (!warm && claudeSessionId) {
  // Still have session ID from before
  return spawnWarmClaude(sessionId, prompt, claudeSessionId);
  // ↑ Uses --resume to restore context, then stays warm
}

How It Works Together

Scenario Behavior Latency
First prompt (cold start) Spawn Claude, save claudeSessionId, keep warm ~3s
Second prompt (<5 min) Reuse warm process, pipe via stdin ~0s
Third prompt (<5 min) Reuse warm process, pipe via stdin ~0s
After 5 min idle Process killed, session ID retained -
Next prompt (after idle) Spawn with --resume, load context, stay warm ~3s
After 24hr session expiry New session, fresh start ~3s

Challenges to Address

stdin protocol Need to delimit prompts in stdin stream. Claude may need --interactive mode.
Output parsing Distinguish which response belongs to which prompt. May need request IDs in stream.
Memory growth Long-running process may accumulate memory. Monitor and restart if needed.
Concurrent users One warm process per user session. Multiple users = multiple warm processes.

Summary

--resume = Restore conversation context to a new process (still pays spawn cost)
Warm cache = Keep same process alive, send prompts via stdin (zero spawn cost)
Best of both = Warm cache for active use, fallback to --resume after 5 min idle

Quick Actions

Original Request

No layout configured

Details

Type General
Status Completed
Created 1 Jan 2026, 11:21 pm
Updated 2 Jan 2026, 3:10 pm
Created By claude

Raw Data

{
  "id": "b9688e4e-b532-48ab-89c0-e2ac2d157eca",
  "type": "general",
  "status": "completed",
  "title": "Warm Session Cache Design",
  "description": "How process caching would integrate with konsole's existing --resume",
  "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 8px 0;\">Warm Session Cache Design</h2>\n<p style=\"color:#7f848e;margin:0 0 20px 0;\">Integrating process caching with konsole's existing --resume mechanism</p>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"color:#61afef;margin:0 0 12px 0;font-size:1rem;\">Current Architecture (2 Layers)</h3>\n<pre style=\"background:#1a1a1a;padding:12px;border-radius:4px;font-family:monospace;font-size:0.8rem;overflow-x:auto;line-height:1.6;margin:0;\"><span style=\"color:#7f848e;\">Layer 1: Konsole Session</span>\n<span style=\"color:#98c379;\">session.ts</span> → <span style=\"color:#e5c07b;\">ses_abc123</span> (persisted to disk, 24hr TTL)\n           → stores <span style=\"color:#c678dd;\">claudeSessionId</span> for resume\n           → tracks kontexts, status, working history\n\n<span style=\"color:#7f848e;\">Layer 2: Claude Process</span>\n<span style=\"color:#98c379;\">claude.ts</span> → <span style=\"color:#e06c75;\">spawnClaude()</span> called PER PROMPT\n          → spawns: <span style=\"color:#e5c07b;\">claude --print --resume {claudeSessionId} \"prompt\"</span>\n          → process exits after each response\n          → <span style=\"color:#c678dd;\">~1-3 seconds startup overhead</span></pre>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;border-left:4px solid #e5c07b;\">\n<h3 style=\"color:#e5c07b;margin:0 0 12px 0;font-size:1rem;\">Key Insight: --resume ≠ Process Reuse</h3>\n<p style=\"color:#e0e0e0;margin:0;font-size:0.9rem;line-height:1.6;\">\nCurrently <code style=\"background:#1a1a1a;padding:2px 6px;border-radius:3px;\">--resume</code> passes the Claude session ID to a <strong>new process</strong>. The new process loads conversation history from Claude's internal storage (~/.claude/), but still pays the full startup cost.\n</p>\n<pre style=\"background:#1a1a1a;padding:12px;border-radius:4px;font-family:monospace;font-size:0.8rem;margin:12px 0 0 0;\">\n<span style=\"color:#7f848e;\">Prompt 1:</span> claude --print \"Hello\"          <span style=\"color:#e06c75;\">→ spawn, run, exit (3s)</span>\n<span style=\"color:#7f848e;\">Prompt 2:</span> claude --print --resume abc \"Hi\" <span style=\"color:#e06c75;\">→ spawn, load, run, exit (3s)</span>\n<span style=\"color:#7f848e;\">Prompt 3:</span> claude --print --resume abc \"Bye\" <span style=\"color:#e06c75;\">→ spawn, load, run, exit (3s)</span>\n                                            <span style=\"color:#7f848e;\">Total: 9s overhead</span></pre>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;border-left:4px solid #22c55e;\">\n<h3 style=\"color:#22c55e;margin:0 0 12px 0;font-size:1rem;\">Warm Cache: Keep Process Alive</h3>\n<p style=\"color:#e0e0e0;margin:0 0 12px 0;font-size:0.9rem;line-height:1.6;\">\nInstead of exiting after each response, keep the Claude process running and pipe new prompts via stdin.\n</p>\n<pre style=\"background:#1a1a1a;padding:12px;border-radius:4px;font-family:monospace;font-size:0.8rem;margin:0;\">\n<span style=\"color:#7f848e;\">Prompt 1:</span> claude --print \"Hello\"          <span style=\"color:#e06c75;\">→ spawn (3s)</span> + run\n<span style=\"color:#7f848e;\">Prompt 2:</span> <span style=\"color:#98c379;\">(stdin) \"Hi\"</span>                    <span style=\"color:#98c379;\">→ immediate (0s)</span>\n<span style=\"color:#7f848e;\">Prompt 3:</span> <span style=\"color:#98c379;\">(stdin) \"Bye\"</span>                   <span style=\"color:#98c379;\">→ immediate (0s)</span>\n<span style=\"color:#7f848e;\">[5 min idle]</span> → kill process\n<span style=\"color:#7f848e;\">Prompt 4:</span> claude --print --resume abc     <span style=\"color:#e06c75;\">→ spawn (3s)</span> + run\n                                            <span style=\"color:#98c379;\">Total: 6s overhead (vs 12s)</span></pre>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"color:#c678dd;margin:0 0 12px 0;font-size:1rem;\">Implementation Changes</h3>\n\n<div style=\"margin-bottom:16px;\">\n<h4 style=\"color:#61afef;margin:0 0 8px 0;font-size:0.95rem;\">1. claude.ts - Process Pool</h4>\n<pre style=\"background:#1a1a1a;padding:10px;border-radius:4px;font-family:monospace;font-size:0.8rem;overflow-x:auto;margin:0;\"><span style=\"color:#7f848e;\">// NEW: Track warm processes</span>\n<span style=\"color:#c678dd;\">const</span> warmProcesses = <span style=\"color:#c678dd;\">new</span> <span style=\"color:#e5c07b;\">Map</span>&lt;<span style=\"color:#e5c07b;\">string</span>, <span style=\"color:#e5c07b;\">WarmClaudeProcess</span>&gt;();\n\n<span style=\"color:#c678dd;\">interface</span> <span style=\"color:#e5c07b;\">WarmClaudeProcess</span> {\n  process: <span style=\"color:#e5c07b;\">Deno.ChildProcess</span>;\n  stdin: <span style=\"color:#e5c07b;\">WritableStreamDefaultWriter</span>;\n  lastUsedAt: <span style=\"color:#e5c07b;\">number</span>;\n  claudeSessionId: <span style=\"color:#e5c07b;\">string</span>;\n}\n\n<span style=\"color:#7f848e;\">// Reuse or spawn</span>\n<span style=\"color:#c678dd;\">function</span> <span style=\"color:#61afef;\">getOrSpawnClaude</span>(sessionId, prompt, claudeSessionId) {\n  <span style=\"color:#c678dd;\">const</span> warm = warmProcesses.<span style=\"color:#61afef;\">get</span>(sessionId);\n  <span style=\"color:#c678dd;\">if</span> (warm && warm.process.running) {\n    warm.lastUsedAt = <span style=\"color:#e5c07b;\">Date</span>.<span style=\"color:#61afef;\">now</span>();\n    warm.stdin.<span style=\"color:#61afef;\">write</span>(prompt); <span style=\"color:#7f848e;\">// Send via stdin</span>\n    <span style=\"color:#c678dd;\">return</span> warm;\n  }\n  <span style=\"color:#7f848e;\">// Cold start - spawn new</span>\n  <span style=\"color:#c678dd;\">return</span> <span style=\"color:#61afef;\">spawnWarmClaude</span>(sessionId, prompt, claudeSessionId);\n}</pre>\n</div>\n\n<div style=\"margin-bottom:16px;\">\n<h4 style=\"color:#61afef;margin:0 0 8px 0;font-size:0.95rem;\">2. Idle Timeout (5 min)</h4>\n<pre style=\"background:#1a1a1a;padding:10px;border-radius:4px;font-family:monospace;font-size:0.8rem;overflow-x:auto;margin:0;\"><span style=\"color:#7f848e;\">// Run every 60 seconds</span>\n<span style=\"color:#61afef;\">setInterval</span>(() => {\n  <span style=\"color:#c678dd;\">const</span> now = <span style=\"color:#e5c07b;\">Date</span>.<span style=\"color:#61afef;\">now</span>();\n  <span style=\"color:#c678dd;\">for</span> (<span style=\"color:#c678dd;\">const</span> [id, warm] <span style=\"color:#c678dd;\">of</span> warmProcesses) {\n    <span style=\"color:#c678dd;\">if</span> (now - warm.lastUsedAt > <span style=\"color:#d19a66;\">5 * 60 * 1000</span>) {\n      warm.process.<span style=\"color:#61afef;\">kill</span>(<span style=\"color:#98c379;\">\"SIGTERM\"</span>);\n      warmProcesses.<span style=\"color:#61afef;\">delete</span>(id);\n      log.<span style=\"color:#61afef;\">info</span>(<span style=\"color:#98c379;\">\"Expired warm process\"</span>, { sessionId: id });\n    }\n  }\n}, <span style=\"color:#d19a66;\">60_000</span>);</pre>\n</div>\n\n<div>\n<h4 style=\"color:#61afef;margin:0 0 8px 0;font-size:0.95rem;\">3. Fallback to --resume</h4>\n<pre style=\"background:#1a1a1a;padding:10px;border-radius:4px;font-family:monospace;font-size:0.8rem;overflow-x:auto;margin:0;\"><span style=\"color:#7f848e;\">// When warm process expires, fall back to --resume</span>\n<span style=\"color:#c678dd;\">if</span> (!warm && claudeSessionId) {\n  <span style=\"color:#7f848e;\">// Still have session ID from before</span>\n  <span style=\"color:#c678dd;\">return</span> <span style=\"color:#61afef;\">spawnWarmClaude</span>(sessionId, prompt, claudeSessionId);\n  <span style=\"color:#7f848e;\">// ↑ Uses --resume to restore context, then stays warm</span>\n}</pre>\n</div>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"color:#56b6c2;margin:0 0 12px 0;font-size:1rem;\">How It Works Together</h3>\n<table style=\"width:100%;border-collapse:collapse;font-size:0.85rem;\">\n<tr style=\"border-bottom:2px solid #444;background:#1a1a1a;\">\n<th style=\"text-align:left;padding:10px;\">Scenario</th>\n<th style=\"text-align:left;padding:10px;\">Behavior</th>\n<th style=\"text-align:right;padding:10px;\">Latency</th>\n</tr>\n<tr style=\"border-bottom:1px solid #333;\">\n<td style=\"padding:10px;\">First prompt (cold start)</td>\n<td style=\"padding:10px;color:#e0e0e0;\">Spawn Claude, save claudeSessionId, keep warm</td>\n<td style=\"padding:10px;text-align:right;color:#e06c75;\">~3s</td>\n</tr>\n<tr style=\"border-bottom:1px solid #333;\">\n<td style=\"padding:10px;\">Second prompt (&lt;5 min)</td>\n<td style=\"padding:10px;color:#e0e0e0;\">Reuse warm process, pipe via stdin</td>\n<td style=\"padding:10px;text-align:right;color:#98c379;\">~0s</td>\n</tr>\n<tr style=\"border-bottom:1px solid #333;\">\n<td style=\"padding:10px;\">Third prompt (&lt;5 min)</td>\n<td style=\"padding:10px;color:#e0e0e0;\">Reuse warm process, pipe via stdin</td>\n<td style=\"padding:10px;text-align:right;color:#98c379;\">~0s</td>\n</tr>\n<tr style=\"border-bottom:1px solid #333;\">\n<td style=\"padding:10px;\">After 5 min idle</td>\n<td style=\"padding:10px;color:#e0e0e0;\">Process killed, session ID retained</td>\n<td style=\"padding:10px;text-align:right;color:#7f848e;\">-</td>\n</tr>\n<tr style=\"border-bottom:1px solid #333;\">\n<td style=\"padding:10px;\">Next prompt (after idle)</td>\n<td style=\"padding:10px;color:#e0e0e0;\">Spawn with --resume, load context, stay warm</td>\n<td style=\"padding:10px;text-align:right;color:#e5c07b;\">~3s</td>\n</tr>\n<tr>\n<td style=\"padding:10px;\">After 24hr session expiry</td>\n<td style=\"padding:10px;color:#e0e0e0;\">New session, fresh start</td>\n<td style=\"padding:10px;text-align:right;color:#e06c75;\">~3s</td>\n</tr>\n</table>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;border-left:4px solid #f97316;\">\n<h3 style=\"color:#f97316;margin:0 0 12px 0;font-size:1rem;\">Challenges to Address</h3>\n<table style=\"width:100%;border-collapse:collapse;font-size:0.85rem;\">\n<tr style=\"border-bottom:1px solid #444;\">\n<td style=\"padding:8px 0;color:#e5c07b;width:150px;\">stdin protocol</td>\n<td style=\"color:#e0e0e0;\">Need to delimit prompts in stdin stream. Claude may need <code style=\"background:#1a1a1a;padding:2px 4px;border-radius:3px;\">--interactive</code> mode.</td>\n</tr>\n<tr style=\"border-bottom:1px solid #444;\">\n<td style=\"padding:8px 0;color:#e5c07b;\">Output parsing</td>\n<td style=\"color:#e0e0e0;\">Distinguish which response belongs to which prompt. May need request IDs in stream.</td>\n</tr>\n<tr style=\"border-bottom:1px solid #444;\">\n<td style=\"padding:8px 0;color:#e5c07b;\">Memory growth</td>\n<td style=\"color:#e0e0e0;\">Long-running process may accumulate memory. Monitor and restart if needed.</td>\n</tr>\n<tr>\n<td style=\"padding:8px 0;color:#e5c07b;\">Concurrent users</td>\n<td style=\"color:#e0e0e0;\">One warm process per user session. Multiple users = multiple warm processes.</td>\n</tr>\n</table>\n</div>\n\n<div style=\"background:#22c55e20;padding:16px;border-radius:6px;border:1px solid #22c55e;\">\n<h3 style=\"color:#22c55e;margin:0 0 12px 0;font-size:1rem;\">Summary</h3>\n<p style=\"margin:0;color:#e0e0e0;line-height:1.6;\">\n<strong>--resume</strong> = Restore conversation context to a <em>new</em> process (still pays spawn cost)<br>\n<strong>Warm cache</strong> = Keep <em>same</em> process alive, send prompts via stdin (zero spawn cost)<br>\n<strong>Best of both</strong> = Warm cache for active use, fallback to --resume after 5 min idle\n</p>\n</div>\n\n</div>",
    "requestedAt": "2026-01-01T13:15:00.000Z",
    "requestId": "518ab0e4-4216-4096-82cb-edbf5c9ad415"
  },
  "createdBy": "claude",
  "createdAt": "2026-01-01T13:21:25.333Z",
  "updatedAt": "2026-01-02T05:10:54.071Z",
  "requestId": "518ab0e4-4216-4096-82cb-edbf5c9ad415"
}
DashboardReportsKontasksSessionsTelemetryLogs + Go