The New Contract Has Two Execution Boundaries
The release note is short, but it defines two materially different trust surfaces. Put headersHelper on a URL marketplace and Claude Code can use its output to fetch the marketplace catalog and archives hosted on the same origin. Put it on one catalog entry and the helper belongs to that plugin's install and update path. The second form runs only after Claude Code shows the command; the non-interactive claude plugin install and update commands ask [y/N], and automation must opt in with -y.
| Scope | When it runs | Use it when |
|---|---|---|
| URL marketplace | Catalog add or refresh, and eligible same-origin archive fetches | Every catalog reader needs one read-only distribution identity |
| Catalog entry | That plugin's install or update, after command disclosure and confirmation | A plugin needs a narrower audience, entitlement, or repository permission |
That separation is the feature. A catalog token should answer “which plugins exist?” An entry token may answer “may this developer download the deployment plugin?” Reusing one broad credential for both paths is operationally easy, but it removes the least-privilege benefit and makes a catalog refresh capable of reaching every protected artifact. The general AI developer tools guide owns Claude Code's place in the tool stack; this article stays with the authentication boundary introduced in 2.1.238.
Configure the Catalog Helper Where the URL Lives
For a project-shared marketplace, the configuration shape is an extraKnownMarketplaces entry whose source is a direct URL. Add headersHelper to that URL source. The helper command must print a JSON object of HTTP header names and string values to standard output. Keep diagnostics on standard error so they cannot corrupt the JSON.
{
"extraKnownMarketplaces": {
"acme-tools": {
"source": {
"source": "url",
"url": "https://plugins.example.com/marketplace.json",
"headersHelper": "/opt/acme/bin/claude-marketplace-headers"
}
}
}
}
#!/usr/bin/env bash
set -euo pipefail
# Example issuer: request a read-only token valid for five minutes.
token="$(acme-auth mint \
--audience claude-plugin-catalog \
--scope plugins:read \
--ttl-seconds 300)"
jq -n --arg token "$token" \
'{"Authorization": ("Bearer " + $token)}'
The five-minute lifetime is an example, not a Claude Code requirement. Set it from your identity provider's policy and the longest catalog or archive request you actually observe. The useful properties are narrower: the token is minted on demand, carries read-only distribution scope, is not embedded in JSON, and cannot be mistaken for a general API credential. Make the helper fail closed: a minting error should produce a non-zero exit, never an empty header object and never a fallback long-lived token.
The release explicitly limits the catalog helper's archive coverage to same-origin fetches. If the catalog is at https://plugins.example.com/marketplace.json but an archive points to https://artifacts.example.net/plugin.zip, do not assume the catalog credential follows it. Either serve the archive from the catalog origin or give that catalog entry its own helper. This prevents a catalog-controlled URL from forwarding your header to an unrelated host.
Use Entry Scope for Stronger Entitlements
A catalog entry can carry its own helper beside an archive source. This is the better boundary when the catalog is visible to the whole engineering organization but one plugin is restricted to release engineers, security staff, or a licensed team.
{
"name": "acme-tools",
"owner": { "name": "Acme Developer Platform" },
"plugins": [
{
"name": "release-controls",
"source": {
"source": "archive",
"url": "https://artifacts.example.net/release-controls-2.4.1.zip",
"sha256": "REPLACE_WITH_THE_ARCHIVE_SHA256"
},
"headersHelper": "/opt/acme/bin/release-plugin-headers"
}
]
}
Now the command-execution moment is later and visible. Browsing or refreshing the catalog does not need to mint the release-plugin credential. Installing or updating release-controls shows the command first and asks for confirmation. Preserve that boundary in team documentation. Do not train users to reflexively pass -y, and do not hide it inside a wrapper that turns every marketplace operation into an unconditional yes. A helper is executable code with access to whatever identity mechanism it calls; disclosure is part of the control, not terminal noise.
Pin the archive with sha256 as well. Authentication decides who may download the bytes; a digest verifies which bytes arrived. They solve different problems, and short token lifetime does not compensate for an unpinned mutable archive. If your wider workflow moves plugin changes through CI, the separation between identity, artifact integrity, and deployment approval mirrors the gates in the AI-assisted CI/CD guide.
Test Five Paths, Not One Happy Install
A successful install proves only that one sequence happened to work while its credential was valid. Exercise the boundaries independently with a test user whose token has read access and no write privileges:
- Catalog add. Start without the marketplace cached. Add the direct catalog URL and confirm the catalog-level helper runs, the request carries the intended header, and no token appears in settings, logs, process arguments, or captured standard output.
- Plugin install. Install the named plugin. For an entry helper, verify that Claude Code displays the exact command and defaults the confirmation to no. Approve it once, then verify the archive digest and installed plugin.
- Marketplace and plugin update. Rotate the issuer credential or let the short-lived token expire, publish a harmless version bump, and test catalog refresh separately from plugin update. This catches helpers that work only on first install.
- Same-origin archive. Put a test archive on the catalog's origin and confirm the catalog helper authorizes that download. Then point a test entry at another origin and confirm it requires its own authentication path rather than receiving the catalog header.
- Authentication failure. Revoke the test identity or have the helper exit non-zero. The operation must fail clearly without replacing a known-good cached plugin, printing the token, or silently retrying with a static secret.
Record server-side request IDs and the token audience, not the token itself. Add a counter for helper failures and 401/403 responses, separated by catalog and entry scope. That is enough to distinguish “the issuer is down” from “this developer lacks the release-plugin entitlement” without turning observability into a credential archive.
The Safe Default Is Narrow and Boring
Use one catalog-level helper when the catalog and all same-origin archives share exactly one read policy. Use entry-level helpers for exceptions. Give every minted credential read-only scope, a purpose-specific audience, and a lifetime long enough for one fetch rather than one workday. Keep token material out of files and stdout beyond the helper's required JSON response. Treat helper changes like any other code that touches credentials: review them, pin their deployment, and test their failure mode.
Finally, check versions before rollout. Marketplace headersHelper is new in Claude Code 2.1.238; older clients do not have this contract. Upgrade the pilot group, test the five paths, then make the minimum version part of your internal installation instructions. For teams still deciding how much should run from the terminal at all, the CLI-first AI development guide covers the broader operating model.
The operating decision
Catalog helper for shared catalog access; entry helper for plugin-specific entitlement. Keep Claude Code's displayed-command and [y/N] confirmation boundary, pin archives, and prove add, install, update, same-origin fetch, and failure separately before rollout.