claude-code

claude-sniff pauses Claude Code's Bedrock invokes

Claude News

claude-code

claude-sniff is a loopback man-in-the-middle proxy that intercepts the Amazon Bedrock invokes Claude Code sends, holding each request until its JSON body is forwarded or dropped, with the listener on 127.0.0.1:9090 and the control UI on 127.0.0.1:8765. The project was posted to Show HN and documented on Github, which describes the setup as one listener, one UI and no run wrapper.

At a glance

  • Only Bedrock Runtime invoke and invoke-with-response-stream calls carrying an x-claude-code-session-id header are held, queued in a global FIFO in which just the head request can be edited before release.
  • An untouched body resumes as the original with no re-signing, an edited body is re-signed with SigV4 from the process's own AWS credential chain, and Drop returns a client-visible error without calling Bedrock.
  • Both toggles start off and are not persisted between runs, Intercept stays disabled until Proxy is on, and switching either off flushes the queue by forwarding held requests as the originals.

Claude Code on Bedrock does not honour ANTHROPIC_BASE_URL, so the usual approach of pointing a client at a local reverse proxy does not apply, which leaves little room to inspect or rewrite what the agent sends before it leaves the machine. A tool that pauses signed InvokeModel traffic at the network layer reads as an answer to that gap, likely useful for auditing prompts, debugging system blocks and testing how the agent handles modified input.

Only invokes carrying x-claude-code-session-id are held

With Intercept on, every Bedrock Runtime invoke and invoke-with-response-stream request that carries an x-claude-code-session-id header stops at the proxy. The head of the global queue is the only entry whose JSON can be edited; the rest wait. Forward releases it, Drop writes an error row to the session's JSONL and returns an error to the client.

Re-signing only happens when the body changes: an unedited request goes out as it arrived, while an edited one is signed again with SigV4 using the credentials of the process running main.py. That path also requires InvokeModel permission on the same models, supplied through --aws-profile, AWS_PROFILE or SSO.

The mitmproxy CA has to be trusted through four environment variables

The first run writes the mitmproxy CA to ~/.mitmproxy/mitmproxy-ca-cert.pem. Each new Claude Code process needs HTTP_PROXY and HTTPS_PROXY pointed at 127.0.0.1:9090, since it does not inherit exports from another shell, and with Proxy off the connection is simply tunnelled against Bedrock's real certificate.

To read the bodies, the CA has to be trusted through NODE_EXTRA_CA_CERTS, SSL_CERT_FILE, REQUESTS_CA_BUNDLE and AWS_CA_BUNDLE, and claude has to be restarted afterwards. The README advises trusting the certificate only while Proxy is on. Sessions with that header then appear under the Sessions tab and on the Proxy page while live.

Prerequisites are Python 3.12 or newer and uv, plus a Claude Code session already reaching Bedrock Runtime with CLAUDE_CODE_USE_BEDROCK=1 in the same region and profile. The UI opens on Sessions and adds Usage, Proxy and Info tabs, with both toggles in the header.

Rows land in logs/<client>/<session-id>.jsonl and costs use eu-central-1 rates

Each observed request produces a row in logs/<client>/<session-id>.jsonl, with the Authorization and x-amz-security-token headers stripped and the bodies stored as they were. Spend is displayed in the sidebar and per request, priced against EU regional on-demand rates for eu-central-1. The logs directory is gitignored.

Model families are derived from keywords in model names or from account-scoped application-inference-profile ids, which the repository does not ship; mapping those takes CLAUDE_PROXY_INFERENCE_PROFILES or a gitignored inference-profiles.json. An unknown model or profile is counted as $0, and pricing is applied at read time rather than written back into the logs.

Usage also reads the journals in ~/.claude/projects, so cost figures appear even with Proxy off. Where the same UUID exists in both logs/ and a journal, the entry is shown once and the MITM dollar figure takes precedence; journal-only rows carry costs without any chat content.

Bedrock responses stay out of scope

Bedrock responses are neither intercepted nor edited, the tool is not a reverse proxy sitting on ANTHROPIC_BASE_URL, and the Proxy and Intercept states are discarded on exit. The repository also ships no request overlays, no sample jailbreaks and no application-inference-profile ids of its own. No roadmap or release schedule accompanies the README.

Comments

No comments yet. Be the first.

Join the conversation

Sign in with Google to leave a comment. Your name and avatar come from your Google profile, and the comment appears after moderation.

We only use your name and avatar from Google. We never store your email address.