60s startup delay in ConPTY: DA1 sentinel never receives response

Resolved 💬 3 comments Opened Mar 19, 2026 by JohanYman Closed Mar 23, 2026

Summary

Claude Code takes ~60 seconds to start when running inside a ConPTY pseudo-terminal (embedded terminals, VS Code integrated terminal on Windows, terminal multiplexers). Running directly in PowerShell starts in ~2 seconds.

Root Cause

Claude's Ink renderer sends an XTVERSION query (ESC[>0q) followed by a DA1 sentinel (ESC[c) during startup:

// From InternalApp (WJ8) when raw mode is first enabled:
setImmediate(() => {
  Promise.all([this.querier.send(WU7()), this.querier.flush()]).then(([K]) => {
    if (K) Rp7(K.name), k(`XTVERSION: terminal identified as "${K.name}"`);
    else k("XTVERSION: no reply (terminal ignored query)");
  });
});

The querier has no explicit timeout — it relies entirely on the DA1 response as a sentinel:

flush() {
  return new Promise((A) => {
    this.sentinels.push(A);
    this.stdout.write(ZO9);  // ESC[c (DA1)
  });
}

Problem: ConPTY swallows the DA1 query (ESC[c]) — it intercepts it internally but does NOT send a response back to the child process's stdin. The XTVERSION query (ESC[>0q) IS passed through to the output pipe, but DA1 is not. Since the DA1 response never arrives, Promise.all never resolves, and Claude blocks for ~60 seconds until some internal Node.js event loop fallback kicks in.

Evidence

Timestamped PTY output from crew-board's embedded terminal (ConPTY, flags=0):

+0.0s  read#1  160 bytes  (ConPTY screen clear)
+0.9s  read#2  11 bytes   (title: "claude")
+1.3s  read#3  27 bytes   (ESC[?2004h ESC[?1004h ESC[>1u ESC[?25l)
+1.4s  read#4  5 bytes    (ESC[>0q — XTVERSION query appears in output)
                           NOTE: ESC[c (DA1) does NOT appear — ConPTY swallowed it
+63.0s read#5  1030 bytes (Claude logo renders — 61.6 seconds later!)
  • ESC[>0q appears in the output pipe (ConPTY passes it through)
  • ESC[c does NOT appear (ConPTY intercepts it internally)
  • Host cannot send DA1 response through ConPTY's input pipe (ConPTY processes VT on its input pipe rather than forwarding to the child)
  • Result: 60-second startup delay every time

Comparison: pwsh starts instantly in the same ConPTY setup. claude --version via cmd /c takes 454ms. The delay is specifically in Claude's interactive terminal initialization.

Suggested Fix

Add an explicit timeout (2-3 seconds) to the querier's flush() method:

flush() {
  return new Promise((resolve) => {
    this.sentinels.push(resolve);
    this.stdout.write(ZO9);  // ESC[c
    // Timeout: if DA1 response doesn't arrive in 3s, resolve anyway
    setTimeout(() => {
      const idx = this.sentinels.indexOf(resolve);
      if (idx !== -1) {
        this.sentinels.splice(idx, 1);
        // Resolve all pending queries as undefined (no response)
        for (const pending of this.pending.splice(0)) pending.resolve(undefined);
        resolve();
      }
    }, 3000);
  });
}

This would reduce the startup delay from ~60s to ~3s in ConPTY environments while maintaining the DA1 sentinel behavior for real terminals.

Environment

  • Windows 11, native PowerShell (not WSL)
  • Claude Code 2.1.79 (npm install)
  • ConPTY via portable-pty (Rust), flags=0
  • Node.js v22 via nvm4w
  • Also affects: VS Code integrated terminal (#24584), any ConPTY host

Related Issues

  • #24584 — Native binary freezes in VS Code terminal (same ConPTY issue)
  • #23211 — Windows Terminal input frozen (ConPTY ANSI processing)
  • #14352 — WSL2 slow startup (different root cause but similar symptoms)

Labels

bug, windows, performance

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗