Preflight Checklist
Feature Description
Current behavior: HTTP hooks support environment variable interpolation in headers values via allowedEnvVars, but the url field is validated as a strict URL format at load time (Zod z.string().url()). This means ${MY_WEBHOOK_URL} in the url field fails with invalid_format.
Requested behavior: Allow $VAR_NAME or ${VAR_NAME} syntax in the url field, with variables resolved from allowedEnvVars — same as headers. If the variable is unset/empty, the hook should silently skip (matching HTTP hooks' existing non-blocking error semantics).
Use Case
We maintain OrchestKit, a public Claude Code plugin with 80 skills, 30 agents, and 105 hooks. We have 12 HTTP hooks across lifecycle events (SessionStart, Stop, SubagentStart, etc.) that forward events to a user-configurable webhook endpoint.
As a public plugin, we cannot hardcode any URL — each user has their own endpoint. The natural pattern is:
{
"type": "http",
"url": "${ORCHESTKIT_HOOK_URL}",
"headers": {
"Authorization": "Bearer ${ORCHESTKIT_HOOK_TOKEN}"
},
"allowedEnvVars": ["ORCHESTKIT_HOOK_URL", "ORCHESTKIT_HOOK_TOKEN"]
}
This fails at plugin load time with 12 invalid_format errors, breaking the entire plugin's hooks (not just the HTTP ones).
Current Workaround
The only workaround is replacing all HTTP hooks with command hooks that spawn a Node process to do fetch() — losing HTTP hooks' built-in benefits (no shell spawn, automatic deduplication by URL, native non-blocking error handling).
No official Anthropic plugin uses HTTP hooks today, so this gap hasn't surfaced internally.
Suggested Implementation
- Move URL validation to runtime (after env var interpolation) instead of schema parse time
- Add
url to the fields that allowedEnvVars applies to (alongside headers)
- If the interpolated URL is empty/invalid, treat it like a connection failure (non-blocking, continue)
Impact
High — prevents public plugins from using HTTP hooks with user-configurable endpoints. Forces degraded command-hook workarounds.
Environment
- Claude Code: 2.1.70
- OS: macOS
- Plugin: OrchestKit v7.1.10
Preflight Checklist
Feature Description
Current behavior: HTTP hooks support environment variable interpolation in
headersvalues viaallowedEnvVars, but theurlfield is validated as a strict URL format at load time (Zodz.string().url()). This means${MY_WEBHOOK_URL}in theurlfield fails withinvalid_format.Requested behavior: Allow
$VAR_NAMEor${VAR_NAME}syntax in theurlfield, with variables resolved fromallowedEnvVars— same as headers. If the variable is unset/empty, the hook should silently skip (matching HTTP hooks' existing non-blocking error semantics).Use Case
We maintain OrchestKit, a public Claude Code plugin with 80 skills, 30 agents, and 105 hooks. We have 12 HTTP hooks across lifecycle events (SessionStart, Stop, SubagentStart, etc.) that forward events to a user-configurable webhook endpoint.
As a public plugin, we cannot hardcode any URL — each user has their own endpoint. The natural pattern is:
{ "type": "http", "url": "${ORCHESTKIT_HOOK_URL}", "headers": { "Authorization": "Bearer ${ORCHESTKIT_HOOK_TOKEN}" }, "allowedEnvVars": ["ORCHESTKIT_HOOK_URL", "ORCHESTKIT_HOOK_TOKEN"] }This fails at plugin load time with 12
invalid_formaterrors, breaking the entire plugin's hooks (not just the HTTP ones).Current Workaround
The only workaround is replacing all HTTP hooks with command hooks that spawn a Node process to do
fetch()— losing HTTP hooks' built-in benefits (no shell spawn, automatic deduplication by URL, native non-blocking error handling).No official Anthropic plugin uses HTTP hooks today, so this gap hasn't surfaced internally.
Suggested Implementation
urlto the fields thatallowedEnvVarsapplies to (alongside headers)Impact
High — prevents public plugins from using HTTP hooks with user-configurable endpoints. Forces degraded command-hook workarounds.
Environment