Stream
claude.stream() returns an IClaudeStream that yields typed events as they arrive from Claude Code.
Iterating Events
for await (const event of claude.stream("Explain generics")) {
switch (event.type) {
case "text":
process.stdout.write(event.content);
break;
case "thinking":
console.log("[think]", event.content);
break;
case "tool_use":
console.log(`[tool] ${event.toolName}(${JSON.stringify(event.input)})`);
break;
case "tool_result":
console.log(`[result] ${event.output}`);
break;
case "turn_complete":
console.log(`Cost: $${event.costUsd?.toFixed(4)}`);
break;
case "error":
console.error(event.message);
break;
}
}Convenience Methods
If you don't need real-time events, use the convenience methods instead:
.text()
Consumes the stream and returns all text content concatenated.
const text = await claude.stream("Hello").text();.cost()
Consumes the stream and returns the final cost snapshot.
const cost = await claude.stream("Hello").cost();
console.log(cost.totalUsd, cost.tokens.input, cost.tokens.output);.result()
Consumes the stream and returns a full TAskResult - same as claude.ask().
const result = await claude.stream("Hello").result();Single-Consumption Rule
A stream can only be consumed once. You must choose one approach:
- Iterate with
for await- get real-time events - Call
.text(),.cost(), or.result()- get the final result
Mixing them throws an error:
const stream = claude.stream("Hello");
for await (const event of stream) { /* ... */ }
// This throws:
await stream.text(); // Error: Cannot call after iteratingIterating a second time yields nothing (the generator is already exhausted):
const stream = claude.stream("Hello");
for await (const event of stream) { /* gets events */ }
for await (const event of stream) { /* silently yields nothing */ }WARNING
If .text(), .cost(), or .result() was called between the two iterations (or before the second one), the second iteration throws a ClaudeError instead of silently yielding nothing. Calling a convenience method marks the stream as consumed, making any subsequent iteration an error rather than a no-op.
Timeouts
Streams have a 5-minute timeout per read operation. If Claude doesn't respond within this window, a TimeoutError is thrown and the process is killed.
Buffer Limits
The NDJSON buffer is capped at 10MB (LIMITS.ndjsonMaxLineChars). If the buffer exceeds this, a ClaudeError is thrown.
Process Cleanup
The spawned process is always killed on any error (timeout, budget, parse error, etc.), preventing orphaned processes.
Stderr Capture
If the process exits with a non-zero code before producing any events, stderr is captured and included in the ProcessError message. This gives clear errors for common failures like "not authenticated" or "rate limited".