Repository navigation
Conversation
…ff the forward proxy In forward-proxy mode every process the session starts inherits HTTPS_PROXY=http://127.0.0.1:<port>, so aws/git/pip/curl run from the Bash tool ride cache-fix. The hook appends the six proxy exports to the session env file with the hop cache-fix itself forwards to (/health https_proxy), or '' when it has none. CACHE_FIX_CHILD_PROXY=keep opts out. Co-Authored-By: Claude <noreply@anthropic.com>
…PROXY cannot route it through CCF fetch honours NODE_USE_ENV_PROXY in Node 24 and the hook hung past its own timeout when the env named CCF as the proxy. node:http with agent:false is direct. Tests now bound the hook's exit and cover a /health that stalls. Co-Authored-By: Claude <noreply@anthropic.com>
CLAUDE_ENV_FILE is sourced by the Bash tool alone, so the hook left stdio MCP servers, command hooks and the statusLine command on the forward proxy. CLAUDE_CODE_SHELL_PREFIX reaches all of them; the replacement follows. Co-Authored-By: Claude <noreply@anthropic.com>
…a CLAUDE_CODE_SHELL_PREFIX In forward-proxy mode every process a session starts inherits HTTPS_PROXY=<cache-fix>. CLAUDE_ENV_FILE reaches only the Bash tool; CLAUDE_CODE_SHELL_PREFIX also wraps command hooks, stdio MCP servers and the statusLine command. The proxy writes the hop it dials to <claude home>/cache-fix-child-proxy-<port> at listen and whenever the hop changes (atomic; empty = direct; absent = unknown; absent under CACHE_FIX_REQUIRE_HOP with no hop, since direct is forbidden there). bin/child-proxy-floor.sh reads it and re-exports the six proxy variables inside the shell's -c string, after the shell's own startup files have run. Co-Authored-By: Claude <noreply@anthropic.com>
…d proxies out of the real Claude home The floor file is written under the Claude config dir, which a spawned forward-mode proxy inherits from the test process: four test files that launch real proxies now point CLAUDE_CONFIG_DIR at a scratch dir, and a port of 0 publishes nothing. Co-Authored-By: Claude <noreply@anthropic.com>
… file Same behaviour, fewer lines: the found flag, the cat and the trailing branch collapse into the loop. Co-Authored-By: Claude <noreply@anthropic.com>
…e home Co-Authored-By: Claude <noreply@anthropic.com>
…ly its exit Co-Authored-By: Claude <noreply@anthropic.com>
…/<port> directory The script looks in CLAUDE_CONFIG_DIR/proxy-floor, then $HOME/.claude/proxy-floor, for any loopback port among the six keys, so a proxy chained in front of cache-fix that publishes to the same directory is handled whichever prefix holds the CLAUDE_CODE_SHELL_PREFIX slot. Co-Authored-By: Claude <noreply@anthropic.com>
…therwise A chain that is configured but wholly refused, a value that is no http(s) URL and a hop URL carrying credentials now remove the floor file (unknown) instead of publishing direct or a credential-stripped URL. Only the HTTPS hop walk drives the file, so an http/https alternation no longer rewrites it, and an empty-chain walk resets that state, which makes the first floor test independent of the order the cases run in. Co-Authored-By: Claude <noreply@anthropic.com>
…the floor is unknown Co-Authored-By: Claude <noreply@anthropic.com>
…does, and ends -c options SHELL as given may be fish or unset. The script now takes CLAUDE_CODE_SHELL, then SHELL (each only if it names bash or zsh and is executable), else zsh then bash from PATH and the usual directories, else /bin/sh. -c is followed by --, so a command string that begins with a dash is a command and not an option cluster. Co-Authored-By: Claude <noreply@anthropic.com>
…lobal path, unknown states The floor is a convention any local proxy may publish to, one slot works with any prefix that honours it. Direct is published only when nothing is configured; credentials in a hop URL are never published (stripped, the hop would answer 407). The prefix runs commands under bash or zsh, not /bin/sh. Co-Authored-By: Claude <noreply@anthropic.com>
…k and a restated comment Co-Authored-By: Claude <noreply@anthropic.com>
… shell Co-Authored-By: Claude <noreply@anthropic.com>
…he first configured candidate At listen the file got an unchecked candidate, which may be the hop that is down. Only answers that need no walk are written there (no chain: direct, or removed under REQUIRE_HOP; configured but unusable: removed). A configured chain leaves a predecessor's file alone and starts one walk; the hop-change listener writes when it lands. A failed rename also removes its temp file. fix(bin): child-proxy-floor.sh runs only the Bash tool under bash or zsh Claude Code's shell choice applies to the Bash tool alone. Hooks, stdio MCP servers and the statusLine are spawned under /bin/sh -c and now stay there. The Bash tool is told by the shell snapshot it sources (snapshot-zsh-, snapshot-bash-), or by its cwd tail when no snapshot could be made. Co-Authored-By: Claude <noreply@anthropic.com>
…he session; a front proxy takes only the prefix line; hooks stay under /bin/sh Co-Authored-By: Claude <noreply@anthropic.com>
…s unknown; docs measure hooks and MCP under /bin/sh Co-Authored-By: Claude <noreply@anthropic.com>
…olveHop() from the test Co-Authored-By: Claude <noreply@anthropic.com>
…he shell from the Bash tool's own clauses A walk at listen with every hop down stamped direct_last, logged "dialling direct" with no dial made, and removed a handover predecessor's good floor file. With a chain configured the file is now left as it is until the first real HTTPS walk. A failed write's temp-file cleanup can no longer throw out of startProxy. The script reads the snapshot clause up to its first ` 2>/dev/null` (or the setup clause Claude Code adds when a prefix is set), so a command that names a snapshot path or `&& pwd -P >| ` keeps its shell. Docs re-measured on Claude Code 2.1.296. Co-Authored-By: Claude <noreply@anthropic.com>
…se, re-measure the Bash-tool and statusLine rows Co-Authored-By: Claude <noreply@anthropic.com>
…t stands among Claude Code's clauses With no shell snapshot Claude Code can put clauses ahead of the setup clause (sandbox TMPDIR export, session env script, PATH export), so the position-0 anchor sent such a Bash-tool command to /bin/sh. Match the setup clause as one of the && -joined clauses with && eval after it. Docs: say so, name the one string this cannot tell apart, and note the prefix path must not contain a space followed by a dash. Co-Authored-By: Claude <noreply@anthropic.com>
codeslake
marked this pull request as ready for review
October 11, 2026 09:45
Contributor
Author
|
Closing unmerged: this approach is withdrawn. The same result needs no product code, only a CLAUDE_CODE_SHELL_PREFIX set by the user; a README note may follow separately. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
In forward-proxy mode Claude Code is pointed at cache-fix with
HTTPS_PROXY=http://127.0.0.1:<port>. Every process the session starts inherits that variable: Bash-tool commands (aws,git,pip,curl), command hooks, stdio MCP servers and thestatusLinecommand. Bulk transfers that have nothing to do with the Anthropic API then run through the proxy.Change
${CLAUDE_CONFIG_DIR:-~/.claude}/proxy-floor/<port>. The file holds a URL when the HTTPS walk lands on a hop, and is rewritten when that hop changes. It is empty when no upstream proxy is configured at all, which means direct. It is absent when the hop is unknown: before the first walk, when a configured chain has no reachable hop, when the value is unusable, or when the hop URL carries credentials. The directory is product-neutral, so any local proxy can publish there.bin/child-proxy-floor.shis aCLAUDE_CODE_SHELL_PREFIXscript. When a loopback port named by one of HTTPS_PROXY, https_proxy, HTTP_PROXY, http_proxy, ALL_PROXY or all_proxy has a floor file, the script exports that floor to all six variables inside the command's-cstring, so a shell startup file cannot undo it. Bash-tool commands run under the bash or zsh that Claude Code chose. Hooks, stdio MCP servers and the statusLine run under/bin/sh, as they do without a prefix.NO_PROXYis never touched. Without a floor file the command runs unchanged.docs/child-proxy-floor.mdand a README subsection. They recommend wiring cache-fix through the settings.jsonenvblock. Aclaudestarted from a Bash command then re-wires itself at boot: measured on Claude Code 2.1.296, a settingsenvHTTPS_PROXY drew 29 of 29 connections against 0 for an inherited one.apiKeyHelper,otelHeadersHelper, Claude Code's owngit/gh, and LSP servers. A non-Anthropic CONNECT from those still reaches the proxy, and the proxy tunnels it blind to its hop.Tests
test/child-proxy-floor.test.mjscovers:.zshenvthat re-exports the proxy port;',$(...), newlines, a leading-);The full suite passes: 1736 tests, 1735 pass, 1 skipped.