Core concepts
The allowed_callers field
The allowed_callers field specifies which contexts can invoke a tool:
{
"name": "query_database",
"description": "Execute a SQL query against the database",
"input_schema": {
// ...
},
"allowed_callers": ["code_execution_20260120"]
}Possible values:
["direct"]- Claude is guided to call this tool directly (default if omitted)["code_execution_20260120"]- Claude is guided to call this tool only from within code execution["direct", "code_execution_20260120"]- Claude may call this tool directly or from within code execution
Both "code_execution_20260120" and "code_execution_20260521" are accepted in allowed_callers and are interchangeable: a request using either code-execution tool version satisfies tools that list either caller. Response blocks always tag the caller as code_execution_20260120 regardless of which version the request declared.
Choose either ["direct"] or ["code_execution_20260120"] for each tool rather than enabling both, as this provides clearer guidance to Claude for how best to use the tool.
allowed_callers controls how the tool is presented to Claude and is validated against tool_choice, but it is not a hard API-level block on direct invocation. Claude is strongly guided to respect it, but your client should still be prepared to handle a direct tool_use for any tool it defines. Do not rely on allowed_callers as a security boundary.
The caller field in responses
Every tool use block includes a caller field indicating how it was invoked:
Direct invocation (traditional tool use):
{
"type": "tool_use",
"id": "toolu_abc123",
"name": "query_database",
"input": { "sql": "<sql>" },
"caller": { "type": "direct" }
}Programmatic invocation:
{
"type": "tool_use",
"id": "toolu_xyz789",
"name": "query_database",
"input": { "sql": "<sql>" },
"caller": {
"type": "code_execution_20260120",
"tool_id": "srvtoolu_abc123"
}
}The tool_id is the id of the code execution server_tool_use block that made the call, so you can match each programmatic tool_use to the code execution run that produced it.
Container lifecycle
Programmatic tool calling uses the same containers as code execution:
Container creation: A new container is created for each request unless you reuse an existing one
Container ID: Returned in responses in the
containerfield, along with anexpires_attimestampReuse: Pass the container ID back on the next request to keep state. While a programmatic tool call is waiting for your result, the container ID is required on that request, not optional: the API rejects the request without it.
Expiration:
expires_attells you how long the container has left. Idle containers are currently reclaimed after about 5 minutes, and no container can be reused more than 30 days after it was created.While Claude's code is waiting for a programmatic tool result, the pending call times out after about 4 minutes and raises a
TimeoutErrorinside the code. Return each tool result well before theexpires_attimestamp on the paused response. See Container expiration during tool call.