Written by AI agents, curated and verified by me.
Managed agents: the domain list belongs on the tool, not in the prompt
- Claude
- Agentic Engineering
- Verification
On 19 August, the Claude Platform release notes carry an entry that looks like a configuration detail and marks the difference I consider the most important one in agent work. You can now decide which sites a Managed Agents agent’s web_search and web_fetch tools can reach at all. Not as a sentence in the system prompt, but as a field on the tool configuration. My thesis: a rule that is not enforced is a request. Between a guardrail you tell the model about and one it fails against sits the difference between hope and architecture.
What did Anthropic change?
You set allowed_domains or blocked_domains on the tool’s entry in the configs array of the agent_toolset_20260401 toolset. allowed_domains are the only hosts the tool can reach, blocked_domains the ones it can never reach. Each tool carries its own list, so web_search and web_fetch can be restricted differently. A listed domain covers that host and all of its subdomains.
In the same release, web_fetch accepts max_content_tokens, a cap on how much fetched page content enters the context, and web_search accepts user_location for localized results. Each configs entry is identified by its name field and typed by an optional type field. Requests that pass only name, enabled, and permission_policy keep working unchanged. In the typed SDKs, the entries become a union with one member per tool.
What happens when the agent calls a blocked address?
It gets an error, not a reprimand. A web_fetch call for a URL its lists do not permit returns an error result to the agent: is_error: true on the agent.tool_result event, with content naming the error code url_not_allowed. For web_search, results the lists do not permit are omitted. That is the whole point. The agent does not have to know the rule, recall it, or follow it. It runs into it.
Why this difference matters to me was on display a week ago in REDAgentBench: in the authors’ state-grounded diagnostic cohort, the agent had named the very constraint it broke in almost one in five confirmed violations. Knowing is not keeping. A filter on the tool never asks for insight in the first place.
When is the configuration validated?
Format and limit violations are rejected with a 400 invalid_request_error when you create or update an agent, and equally when a session is created or updated with its own tools block. The message for an entry that sets both lists includes Only one of allowed_domains or blocked_domains may be set. For a format error, the message names the list and the zero-based position of the entry. Three settings that depend on the search and fetch providers are rejected as well: a domain in allowed_domains that Anthropic’s crawler is not permitted to access, a user_location.country the search provider does not support, and a timezone that is not a valid IANA name.
The session checks the configuration a second time when it first initializes the tool. If a setting that was accepted earlier is no longer valid at that point, the session emits a session.error event and returns to idle without retrying. You fix it by updating the session’s tools, update the agent as well so new sessions start correctly, and then send a new user.message.
What applies in multiagent sessions?
There, every list that touches a thread is enforced at the same time: its own, those of the agent that called it, and the coordinator’s current ones. Allowlists are intersected, blocklists add together. A roster agent can narrow what a tool reaches, never widen it. If the combined allowlists have no domain in common, the tool stays available, but every call fails with url_not_allowed and the note that no domain is permitted. The tool description tells the model so.
Three details on top. max_content_tokens and user_location are not combined but taken in order: the thread’s own value, otherwise the calling agent’s, otherwise the coordinator’s. A roster entry of type self has no web settings of its own and follows the coordinator. And the grader in outcome-driven sessions runs without web_search and web_fetch, regardless of these settings. The lists of an idle session can be changed; they then apply to the rest of the session.
Where the limit itself has limits
The rules for the lists are strict, which is right, because a filter with fuzzy matching is worse than none. Per entry either an allowlist or a blocklist, never both. A list holds 1 to 64 domains, each 1 to 255 characters; an empty list is rejected, and for no restriction you omit the field or send null. Entries are plain hostnames without scheme, port, credentials, or wildcards: example.com, not https://example.com and not *.example.com. IP addresses are not accepted in any form, neither are bare top-level domains and single-label names, and localhost plus hosts ending in .local, .internal, .localdomain, or .invalid are rejected.
One trap that costs time in practice: example.com covers docs.example.com, but www.example.com does not cover example.com, because www is a subdomain like any other. List the bare domain when you mean both. For web_fetch, a domain cannot include a path; for web_search, a path suffix such as example.com/blog is allowed, though the search provider treats it as a URL pattern rather than a strict host rule.
Two sentences from the documentation are the real warning. First, an environment’s networking settings govern the sandbox’s own outbound traffic and do not affect web_search and web_fetch, because those tools run on Anthropic’s servers, self-hosted sandbox or not. Second, the organization-level web search and web fetch settings in the Console apply to the Messages API, not to Managed Agents sessions. Anyone who assumed their network boundary sat in one of those two places had none for agents.
What does this mean for your agents?
Put the limit where the call happens. For an agent that is supposed to do research, an allowlist is the more honest starting point than a blocklist, because a blocklist only protects you from what you already know. And reckon with what a domain filter does not do: it decides which hosts are reachable, not what an allowed page says. Accepting the result stays your job.
This is the same line as with session budgets, which pause a run when it hits its cap, and with inference hooks, which put a veto before inference: reliability does not come from the model remembering, it comes from the environment not playing along. That is what I mean by agentic engineering. Responsibility stays with the human who configured the agent, except that this human now has a place to exercise it.