8 min read

CDN purge scope previews for AI agents

CDN purge scope previews show AI agent operators the host, path, tag count, and estimated reach before targeted or purge-all actions run.

CDN purge scope previews for AI agents

An AI agent should never ask for approval to "clear the CDN cache." That phrase hides the only facts an operator needs before authorizing the action: which host, which path, how many tags, and how much cached content may stop serving.

A useful CDN purge scope preview turns the final request into a compact statement of blast radius. It must also put a targeted invalidation in a different risk class from a purge-all operation. I have watched broad purges turn a routine release into an origin traffic event because the approval dialog made a wildcard look like one harmless path. The request was syntactically small. Its effect was not.

The right design does more than add a confirmation box. It normalizes the provider request, classifies its scope, estimates the reach with honest uncertainty, and binds the operator's approval to those exact parameters. If the agent changes a host, path, tag, environment, or purge mode after approval, the gateway must ask again.

A purge request needs an impact model

CDN purge scope is the set of cached representations that a provider may invalidate, not the number of strings in an API request. One wildcard can cover a distribution. One tag can refer to thousands of unrelated URLs. One URL can have several cached variants because the cache varies on query strings, headers, cookies, device type, or language.

This is the first distinction teams tend to blur: request size is not effect size. Amazon CloudFront makes the mismatch explicit in its documentation. A wildcard invalidation path counts as one submitted path even if it invalidates thousands of files. Billing units describe the request, not its reach. An approval card that says "1 path" without saying that the path is /* gives the operator a technically true but operationally useless fact.

Model the proposed action along four axes:

  • Target: the CDN account, service or distribution, environment, and hostname.
  • Selector: exact URL, path prefix, wildcard, cache tag, surrogate key, or provider-wide purge flag.
  • Semantics: how selectors combine, which variants they cover, and whether the provider will invalidate or delete cached objects.
  • Consequence: the estimated number of objects or requests affected, expected refill behavior, and whether stale content can still serve.

The model belongs in the execution gateway, close to the credentials and provider adapter. Do not let the agent assign its own risk label. The agent can propose a purge, but code that understands the provider's API must calculate what that proposal means.

This separation matters because provider vocabulary is inconsistent. Fastly calls its grouping label a surrogate key. Google Cloud and Akamai use cache tags. Cloudflare supports tags, hostnames, URL prefixes, individual files, and purge everything. CloudFront supports paths, wildcards, and cache tag invalidation. A portable agent tool can expose one tidy interface, but the preview must preserve the provider's actual matching rules.

Before an execution component displays anything, it should resolve aliases, canonicalize hosts, decode and normalize paths according to the provider's rules, expand any convenience options, and identify the effective environment. The preview then describes the request that will be signed and sent. Showing the agent's earlier, friendlier input creates a gap where normalization can widen the scope without the human seeing it.

Targeted invalidation and purge-all are different actions

Targeted invalidation selects content by an exact URL, a bounded path or prefix, one or more tags, or an intersection of supported selectors. Purge-all discards the useful state of an entire service, zone, or distribution. Treating them as two values in the same dropdown understates the difference.

The classification must follow effect, not endpoint name. These requests all deserve a purge-all label:

  • A provider's explicit purge_everything flag.
  • A distribution path of /*.
  • A wildcard or prefix that normalizes to the root.
  • A tag known by local convention to mark every response in a service.
  • A list of selectors whose union covers the configured host set.

The last two cases require local metadata. A provider may not know that release-current appears on every object, but the deployment system that applies the tag can record that fact. If the gateway cannot prove a selector is bounded, it should mark reach as unknown and raise the approval tier. Unknown is a valid result. Quietly treating unknown as small is not.

Targeted does not mean safe. A /products/ prefix on a large storefront may cover most traffic, and a tenant:42 tag may cross several hosts. The label means the request has an expressed boundary that the preview can show. The operator still needs an estimate of what lies inside that boundary.

Purge-all needs a visually and mechanically separate flow. Require an explicit action name such as purge_all, not an empty selector that the adapter interprets as everything. Reject blank host and path fields in targeted mode. Make the operator approve the production environment and the entire service as named targets. Do not allow a general session approval to absorb this action merely because the same agent made a harmless URL purge earlier.

This is one place where I argue against a popular recommendation: "Just require confirmation for every purge." Repetition trains people to approve the shape of a dialog, not read its content. A single-file invalidation during a release and a whole-distribution purge should not present the same button, warning, or authentication step. Human approval helps only when the interface makes the material difference obvious.

Host, path, and tag count belong above the button

The approval card should lead with the effective target and scope, because operators read under time pressure. Put the provider and production environment first, then the hostname, normalized path, tag count, estimated reach, and operation class. Supporting details can expand below, but the facts that change the decision must stay visible without a click.

A provider-neutral preview can use this shape:

{
  "operation": "targeted_invalidation",
  "provider": "example-cdn",
  "environment": "production",
  "hosts": ["assets.example.test"],
  "paths": ["/releases/2026-07-24/*"],
  "tag_count": 2,
  "tag_samples": ["release:842", "asset:bundle"],
  "selector_logic": "host AND path AND (tag OR tag)",
  "estimated_reach": {
    "objects": {"low": 1600, "high": 2300},
    "method": "tag-index snapshot",
    "observed_at": "2026-07-24T14:31:08Z"
  },
  "refill": "origin requests expected on subsequent misses"
}

Those numbers are illustrative, not a promise that a CDN can count every live edge object. The important part is the output shape: a range, its method, and its observation time. If the estimator has no defensible input, return "objects": "unknown" and say why.

Show all hosts when there are only a few. For a long list, show the count and the first few sorted names, with an explicit affordance to inspect the rest. Never summarize a mixed production and staging list as "12 hosts." Environment boundaries carry more decision weight than the count.

Paths need both the normalized value and the matching rule. /picture* and /picture/* are not the same selector on Google Cloud CDN: the first also matches paths such as /pictures/dog.jpg and /picture1.jpg, while the second stays under the directory. CloudFront requires a wildcard at the end to make it a wildcard; an asterisk elsewhere is literal. A preview that prints only the raw characters makes the operator remember provider grammar at exactly the wrong moment.

Tag count also needs careful wording. "2 tags" means two selectors, not two cached objects. Show the actual tags unless they contain sensitive tenant information; if they do, show stable redacted labels plus a secure detail view. State whether tags combine with OR or AND. Google Cloud CDN treats multiple tags in one request as OR, while combining tag filters with host and path matchers narrows the result through intersection. That small line of logic often explains most of the blast radius.

Estimated reach must admit what the CDN cannot count

An estimated reach should answer "how much cache state might change?" without pretending a distributed cache is an inventory database. Edge objects appear and disappear through expiration, eviction, regional demand, and background refill. Many CDN purge APIs accept a selector but do not return a preflight count.

Use the best available evidence in a fixed order. A recent provider count is strongest when the API offers one. Next comes a deployment-owned tag index that records which URLs received each tag. Then use request logs or cache-status telemetry over a stated window. A configured route catalog can provide a coarse upper bound. If none of those exists, report unknown.

Each estimate should carry four properties:

  • A unit, such as cached objects, URL variants, or recent cache-hit requests.
  • A point estimate or range, never an unlabeled integer.
  • A source and observation time.
  • A confidence label derived by code from the source type and age.

Do not convert recent request volume into an object count. "About 80,000 cache-hit requests in the last hour matched this prefix" is useful impact evidence, but it does not mean 80,000 objects will be invalidated. Show both measures when available: estimated objects describes cache state; recent hits describe likely refill pressure and user exposure.

For an exact URL, reach still may exceed one. CloudFront documentation notes that invalidating a file also invalidates cached variants based on forwarded cookies or headers. Query string behavior depends on the configuration and selector. The preview should say "1 URL, all cookie and header variants" when that is the effective behavior. A bare object count of one would hide the part that matters.

For tags, estimate the union, not the sum. If release:842 covers 1,700 objects and asset:bundle covers 900, overlapping objects must count once. When the provider applies tags with OR, adding the two counts can overstate reach. Overstatement is safer than understatement for an approval threshold, but it still erodes trust. Calculate a real union when the local index can do it, or label the total as an upper bound.

For purge-all, do not waste time manufacturing a precise number. Say "entire production service," show the configured host count, and add recent cache-hit volume as an origin pressure indicator. The action class already tells the operator the cache boundary. False precision makes the card look informed while adding nothing to the decision.

The preview must expose refill consequences

Know which agent requested it
The session approval card leads with the agent process's code-signing authority.

A purge changes where subsequent requests go, so the approval needs to describe the refill behavior as well as the selector. The operational risk is often not stale content disappearing. It is a concentrated wave of misses reaching an origin that was sized on the assumption that the cache would absorb them.

Google Cloud's documentation recommends invalidating only what is necessary because broad invalidation can push requests that caches served back to instances or buckets. It also says to confirm that the origin already returns the correct content, or the CDN may cache the wrong response again. That second point deserves a precondition in the agent workflow: verify the new object at origin before proposing the purge.

Fastly draws another useful distinction between hard and soft purge. A hard purge makes the cached content unavailable for future lookups. A soft purge marks it stale, which can allow stale delivery while the cache revalidates, depending on configuration. Fastly does not offer soft purge for purge-all. An approval that says only "purge" discards this operational difference.

The preview should therefore include:

  • Whether the action is hard invalidation, soft invalidation, or provider-specific deletion.
  • Whether stale content may serve during refresh.
  • The recent cache-hit request rate for the selected scope, if available.
  • The origin or backend group that will receive misses.
  • Whether an origin readiness check passed and when it ran.

Avoid promises such as "2,300 origin requests will occur." Request coalescing, regional distribution, browser caches, shielding, and fresh fills all affect the actual load. Use measured recent traffic and describe it honestly: "The selected scope served 46,000 cache hits in the previous 15 minutes." That tells an operator far more than an invented prediction.

The agent should not run its own readiness check through an unrestricted shell and summarize the result. The gateway should perform a defined check against the intended origin, record the response status and content version, and attach that evidence to the preview. Otherwise a compromised prompt can claim the origin is ready in the same conversation that asks for approval.

Normalization closes the gap between display and execution

The gateway must approve a canonical action, then execute that same action. If the UI renders one representation while the provider adapter sends another, the approval becomes theater.

Canonicalization starts with typed fields. Separate hosts, paths, tags, purge_all, soft, provider, service_id, and environment. Do not accept a free-form curl command as the approval object. The adapter may eventually produce HTTP, but policy and display code should operate on validated data.

Then apply provider rules before classification. Lowercase hostnames, remove a trailing DNS dot, reject embedded credentials, resolve the service alias, and parse paths without treating a fragment as part of the request. Preserve path case when the CDN treats it as significant. Apply the same URL normalization or rewrite awareness that the provider uses. Cloudflare warns that prefix purges involving Transform Rules need the post-transformed origin URL. CloudFront advises invalidating both the viewer URI and rewritten URI when a viewer request function changes the path. A preview should show both effective paths instead of silently adding the second.

One compact classification function can enforce the dangerous cases after normalization:

if purge_all is true:
    return PURGE_ALL
if any normalized path covers the root:
    return PURGE_ALL
if any tag is cataloged as service_wide:
    return PURGE_ALL
if selectors are empty:
    return REJECT
return TARGETED

Provider adapters need tests built from their own grammar. Include root paths, encoded separators, repeated slashes, trailing slashes, wildcard placement, empty arrays, mixed hosts, query strings, and rewritten URLs. Property tests can assert that normalization never makes the execution scope broader than the displayed scope. Regression fixtures should store the normalized preview beside the exact outbound request.

Finally, calculate a digest over the canonical action and preview-critical metadata. The approval record should include the actor, agent process, tool name, normalized parameters, environment, estimate timestamp, digest, and expiry. OWASP's AI Agent Security Cheat Sheet recommends binding approval to the exact action with the actor, tool, target, normalized parameters, time, and expiry. That is the right standard. A human decision about one digest cannot authorize a later request with a different path.

Approval should fail closed when scope drifts

Trace the whole agent run
The Sessions journal connects a purge call to the agent process that made it.

Any material change after preview must invalidate approval. Material fields include provider, account, service, environment, host, path, selector logic, tags, purge mode, and the targeted versus purge-all class. Changing the estimate alone may or may not require another prompt, but crossing a configured impact threshold always should.

Use a short approval lifetime because cache state and traffic move. If an agent waits through another deployment, the path may now contain different objects and the origin readiness evidence may be stale. Expiry should force regeneration of the preview, not merely another click on old data.

The Model Context Protocol tool specification says applications should keep a human able to deny tool invocations and should present confirmation prompts. That is sensible, but a generic confirmation is too weak for destructive infrastructure calls. The host application may know the tool name and JSON arguments, yet only the execution adapter knows that a provider alias maps to production or that / plus a wildcard means everything. Put the meaningful preview at the component that can interpret and enforce those facts.

Approval also needs independence from agent-controlled text. The agent can supply a reason, such as "remove the recalled product image," but render it in a secondary area clearly labeled as the agent's explanation. Generate the scope facts from trusted code and provider configuration. Do not allow Markdown, terminal escape sequences, or arbitrary HTML in any field on the approval card.

High-impact actions deserve stronger friction. A targeted exact-URL purge may require one click. A broad prefix can require a deliberate confirmation with the scope restated. Purge-all should require separate authentication and should not inherit approval from the surrounding agent session. Sallyport can keep the credential outside the agent, show an approval for each use of a protected CDN API key, and log the resulting HTTP call; the provider adapter still needs to supply the normalized scope fields that make that approval useful.

Failures must close the gate. If the estimator times out, show unknown rather than zero. If normalization fails, reject rather than pass raw input through. If audit logging fails, do not execute. If the digest differs at send time, discard the approval and build a fresh preview.

Audit records need the decision and the result

A purge audit trail should preserve what the human saw, what the gateway sent, and what the CDN returned. Logging only the agent's tool request cannot prove that normalization, approval, and execution referred to the same scope.

Record the canonical request, rendered preview fields, estimate source, approval digest, approver identity, approval time, execution time, provider request identifier, and provider response. Mark whether the provider accepted, completed, partially completed, or rejected the operation. If the provider exposes later status, append status observations instead of rewriting the original event.

Keep the estimate separate from the result. An estimate of 2,000 objects remains an estimate even if the provider returns success. Most success responses mean the provider accepted a selector, not that it found exactly that many cached objects. Auditors should be able to tell which claims came from local inference and which came from the CDN.

CloudFront documentation says an invalidation cannot be canceled after submission because edge locations begin processing it quickly. That makes the pre-execution record especially important. A revoke button can stop a future agent call, but it cannot pull back a purge already distributed to edges. The audit interface must not imply otherwise.

For investigation, make these questions answerable without reading a chat transcript:

  • Which signed agent process proposed the action?
  • Which human approved which canonical digest?
  • Did the card classify the action as targeted or purge-all?
  • What hosts, paths, and tags appeared on the card?
  • What did the reach estimator know at that time?

The agent's conversational rationale is supporting context, not authority. Chats can be truncated, summarized, or influenced by untrusted content. The execution journal is the durable record of the action.

Tamper evidence matters when an autonomous process can make repeated infrastructure calls. Sallyport records agent sessions and individual calls from one encrypted, hash-chained audit log, so a team can verify the chain separately from reading its contents. That does not make a bad purge reversible, but it gives responders a defensible sequence of proposal, approval, and execution.

A worked failure shows why four fields matter

Keep the CDN token offscreen
The agent sends an MCP action while Sallyport performs the authenticated HTTP request.

Consider an agent preparing a storefront release. The task says to refresh the new product assets after deployment. The agent sees a build manifest with /products/ and chooses a prefix purge because it is simpler than enumerating hashed files.

The raw request contains one path. A weak dialog shows "Purge 1 path?" and the operator approves. The CDN interprets the prefix across every configured hostname, including the public store, a regional host, and an image host. The route also contains product pages, thumbnails, inventory fragments, and older release assets. Popular objects disappear from cache together, then refill from the same origin group.

A useful preview changes the decision before execution. It shows:

  1. Host: three production hosts, with their names visible.
  2. Path: /products/*, described as a recursive prefix rather than one file.
  3. Tags: none, even though the current release has a dedicated tag.
  4. Estimated reach: 38,000 URL variants and 1.2 million recent cache-hit requests, both labeled with their sources and windows.

The operator rejects the request. The agent then proposes the release tag on the asset host only. The gateway resolves 1,840 indexed objects, notes that two tag values combine with OR, and shows that the action excludes product HTML and inventory responses. The origin check confirms the current release identifier. The operator approves that narrower digest.

The numbers in this scenario are illustrative; the failure pattern is common because prefix syntax looks cheap. The remedy is not a smarter agent prompt. The execution boundary must make broad selectors legible and give the human a narrower option.

The same pattern catches a different error: an agent asks to purge staging, but a service alias resolves to production. If the preview says only "service storefront," the operator may miss it. If it leads with "production" and lists the public hosts, the mismatch is plain.

This walkthrough also explains why tag count cannot replace reach. One release tag may identify 1,840 objects, while twenty exact URL tags may identify twenty objects. Display selector count and estimated matches as separate facts. One describes the request. The other describes its likely effect.

Ship the safety boundary as an executable contract

Teams should implement purge previewing as a contract between the agent tool, provider adapter, approval UI, and audit log. The contract is small enough to test: normalized inputs go in, a classified and digest-bound preview comes out, and execution accepts only an unexpired approval for that digest.

At minimum, require these invariants:

  • Targeted mode has at least one non-root selector and an explicit environment.
  • Purge-all mode uses its own action and cannot arise from blank fields.
  • The displayed host, path, tag count, and selector logic come from canonical parameters.
  • Reach is a sourced range, upper bound, traffic measure, or explicit unknown.
  • Execution recomputes the digest and refuses changed parameters.

Run the adapter against recorded fixtures for every supported CDN operation. Compare the outbound request with the preview snapshot. Add a canary service whose origin can tolerate a purge, then test exact URL, prefix, tag union, host restriction, rewritten path, and purge-all behavior. A dry run that merely echoes agent input proves nothing; the test must exercise normalization and provider request construction.

Keep versioned content as the normal release path. Google Cloud documentation recommends suitable expiration times or versioned URLs instead of routine invalidation, and that advice is sound. Purges are for corrections, recalls, and cases where waiting for TTL is unacceptable. An agent that purges on every deployment turns an exceptional control into a hidden dependency on origin capacity.

When a purge is justified, the preview should make a fast approval possible. An operator should see assets.example.test, /releases/842/*, two tags, and an estimated 1,600 to 2,300 objects without decoding provider JSON. For purge-all, the same position on the card should say "entire production service" and refuse to soften that statement with a small request count.

The test I use is blunt: could an operator distinguish a single asset refresh from a whole-service purge in two seconds, using only trusted fields above the approval button? If not, the agent is not ready to hold that CDN action.

FAQ

What should a CDN purge approval preview show?

Show the effective provider and environment, every host or a clearly inspectable host count, normalized paths, tag count, selector logic, and estimated reach. Put the targeted or purge-all classification above the approval button.

Is a single wildcard path a small invalidation?

No. A path such as /* may invalidate an entire distribution even though the API counts it as one submitted path. Classify by the content matched, not by the number of request fields.

How can an agent estimate CDN purge reach?

Use a provider count when one exists, then a deployment tag index, recent cache telemetry, or a route catalog. Report the unit, source, observation time, and either a range or an explicit unknown.

Does one cache tag mean one cached object?

No. One tag can label many URLs and all their cached variants. Show tag count separately from estimated object reach, and state whether multiple tags combine with OR or AND.

Should every CDN purge require the same confirmation?

No. Reusing one prompt for exact-URL invalidation and purge-all encourages automatic approval. Increase friction with blast radius, and require separate authentication for a whole-service purge.

Why does an exact URL purge affect multiple variants?

A CDN may store versions that vary by query string, cookie, header, device, or language. The preview should name which variants the provider invalidates instead of calling the action one object.

Can a CDN purge be canceled after approval?

Do not design around cancellation. CloudFront states that invalidations cannot be canceled after submission, and other CDNs distribute purge work quickly. Put the reliable control before execution.

What happens when estimated reach is unavailable?

Display unknown, explain which evidence is missing, and raise the approval tier. Never substitute zero or allow the agent to invent a count.

How do you bind approval to the actual purge request?

Canonicalize the provider, service, environment, hosts, paths, tags, and purge mode, then hash that action. Execute only when an unexpired approval references the same digest.

Are versioned URLs better than routine cache purges?

Usually, yes. Versioned URLs and suitable TTLs avoid synchronized refill pressure and make releases easier to reason about. Keep invalidation for corrections and cases where stale content cannot wait.

Sallyport

Sallyport runs API calls and SSH commands for your AI agent. The keys stay in a local vault on your Mac; you approve each run and every action lands in a sealed journal.

© 2026 Sallyport · Open source under Apache-2.0 · Oleg Sotnikov