Skip to content

[runtime][P2] claude-agent-sdk default spawn — stdin not inherited (latent TTY risk in interactive scenarios) #148

@s2agi

Description

@s2agi

Background

While code-tracing the #136 / #138 macOS setRawMode errno 5 chain (the claude-code-cli runtime fix shipped in v0.10.0 via launchAgent's await-child Promise), I noticed an independent latent issue in the claude-agent-sdk runtime path that no user has triggered yet but could surface the same kind of TTY problem in interactive scenarios.

Filed today per a commitment to 通信龙 (commhub message 5f9f9a29, post-v0.9.2 ship): "today/明天 open separate track".

Observation

The claude-agent-sdk runtime path doesn't invoke claude-code-cli directly. agent-node uses query() from @anthropic-ai/claude-agent-sdk, which spawns the bundled claude binary as a child process:

agent-node/src/cli.ts:679   pathToClaudeCodeExecutable: claudePath  // passed to query()
agent-node/src/cli.ts:705   for await (const message of query({ prompt, options }))

The SDK's Options type documents an escape hatch for the spawn:

node_modules/@anthropic-ai/claude-agent-sdk/sdk.d.ts:1791
  spawnClaudeCodeProcess?: (options: SpawnOptions) => SpawnedProcess

agent-node does not currently set spawnClaudeCodeProcess, so the SDK falls back to its internal default spawn. Per the SDK type docs ("When provided, this function is called instead of the default local spawn") and the way query() consumes the agent stream over stdout, the default spawn very likely uses stdio: ['ignore' | 'pipe', 'pipe', 'pipe'] — i.e. stdin is not inherited from the parent terminal to the spawned claude binary.

Why nothing's on fire today

The claude-agent-sdk runtime path is primarily exercised in fan-out / batch scenarios where no user TTY interaction is expected. claude-side calls like setRawMode are skipped when no controlling TTY is present (or fall through silently). So the gap exists but doesn't bite.

If/when an interactive use case for the claude-agent-sdk runtime emerges (think: anet node start <alias> against a --runtime claude-agent-sdk node, where the user types into the spawned claude binary), the same family of setRawMode errno 5 issues that the claude-code-cli runtime had with #136 / #138 could re-surface in this codepath.

Suggested investigation (P2, no urgency)

  1. Confirm the SDK default spawn shape by checking the minified sdk.mjs (or running a quick tee/strace probe on what fd 0 looks like inside the spawned child). My current claim is inferred from the type docs + the fact that the SDK consumes the agent stream via stdout pipe — not directly proven.
  2. If confirmed: agent-node should opt-in to spawnClaudeCodeProcess and pass stdio: ['inherit', 'pipe', 'inherit'] (or equivalent) so stdin is a real PTY when the user is interactive, while keeping stdout pipe for the SDK's stream consumption.
  3. Add an interactive scenario to the release-gate-playbook.md (#85) so future regressions in this lane are caught the way pexpect + chain-test caught the v0.9.2 chain.

Cross-references

Acceptance criteria

  • Confirm or disprove the default-spawn-not-inherit-stdin claim
  • If confirmed: ship spawnClaudeCodeProcess opt-in in agent-node (Method B 2-phase, per feedback_npm_publish_two_phase)
  • Add claude-agent-sdk interactive smoke case to release-gate playbook
  • Cross-link this issue's resolution from the code-trace doc

Author-Agent: 通信工程马
Priority: P2 — no user-facing impact today, latent risk if claude-agent-sdk interactive flow ever lands
Estimated effort: ~1.5h investigation + ~30min ship (if fix needed) + playbook addendum

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions