The Agent SDK is the library that lets your own program run Claude Code and read its messages. A run used to end as soon as the SDK received the result message. Now the SDK starts Claude Code with CLAUDE_CODE_SDK_READS_SESSION_STATE set to 1, unless you already set it yourself (in any upper or lower case). Claude Code then reports each change in its session state, such as busy or idle, to the SDK, and the SDK uses those reports to decide when the run is over. These reports are not sent when CLAUDE_CODE_EMIT_SESSION_STATE_EVENTS is set. The SDK removes them from the message stream, so your program never sees them.
After a result arrives, the SDK:
- ends the run at once if it has never seen a state report, or if your query has no two-way parts such as hooks,
canUseTool, in-process MCP servers or elicitation handlers - otherwise waits for the state to become idle, then ends the run
- ends the run anyway if idle has not arrived within a time limit, 600000 ms (10 minutes) by default
- stops that timer while Claude Code is waiting on you to approve an action
A state other than idle reported after the result reopens the run. You can change the time limit with CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS; a value of 0 or less turns it off. When your input stream ends and the query has two-way parts, the SDK now waits for the whole run to end, not just the first result, and a single-turn query closes its input when the run ends.
Queries that use hooks, canUseTool or in-process MCP servers no longer stop while background work is still running. If you build on the SDK, a run can now last up to 10 minutes past its result message by default, so check any code that assumes the result is the end.
Exactly what ending the run shuts down in each input mode, single-turn versus streaming, is not settled.
New in this build: CLAUDE_CODE_SDK_READS_SESSION_STATE