Architecture
Request flow
Section titled βRequest flowβAI CLI (claude-code, claude-cli, ...) β β HTTP to 127.0.0.1:3817 βΌβββββββββββββββββββββββββββββββββββββββββββββββββ sotatek-proxy (Gin engine, loopback bind) ββ ββ recoveryLogger panic recovery ββ requestLogger scrub Authorization, ββ x-api-key, drop query ββ MiddlewareGitRemote ββ β ββ ββ extract peer port from RemoteAddr ββ ββ inspect.GetPidByPeerPort β PID ββ ββ inspect.GetCwdByPid β CWD ββ ββ walk parents (β€3) for .git ββ ββ cache.Get(pid) [verify CWD] ββ ββ git.GetRemoteRaw(cwd) (2s timeout) ββ ββ inject X-Git-Remote (base64) ββ ββ ReverseProxy (NoRoute) ββ ββ stamp User-Agent: sotatek-proxy/X ββ ββ preserve original in ββ β X-Forwarded-User-Agent ββ ββ FlushInterval=-1 (SSE-safe) βββββββββββββββββββββββ¬ββββββββββββββββββββββββββ β HTTP/2 (ForceAttemptHTTP2) βΌ https://bifrost.sotatek.works/anthropic/v1/*Middleware chain
Section titled βMiddleware chainβThe order matters. Each layer runs in this order on the way in, reverse on the way out.
| # | Middleware | Purpose |
|---|---|---|
| 1 | recoveryLogger | Panic recovery; never echoes request headers. |
| 2 | requestLogger | Compact structured log per request: method, path, status, latency, client_ip, has_auth/has_api_key booleans, has_query flag. Authorization values are never logged. |
| 3 | MiddlewareGitRemote | Resolves the calling PID and CWD, runs git remote -v, base64-encodes the result, sets X-Git-Remote. Strips any client-supplied X-Git-Remote first. |
| 4 | ReverseProxy (NoRoute) | Forwards to upstream 1:1, stamps User-Agent, streams SSE without buffering. |
Process inspection (PID β CWD β git)
Section titled βProcess inspection (PID β CWD β git)βThe proxy resolves the clientβs TCP peer port (the port your CLI used to connect) back to a PID, then to a CWD, then walks up to 3 parent directories looking for .git.
| OS | Implementation |
|---|---|
| macOS | lsof -iTCP:<port> -sTCP:ESTABLISHED -F pn (PID), lsof -p <pid> -d cwd -F n (CWD). 2 s exec timeout. |
| Linux | Reads /proc/net/tcp[6] to map port β inode, scans /proc/*/fd/ for the matching socket, then reads /proc/<pid>/cwd. Same-user only. |
| Windows | GetExtendedTcpTable for IPv4/IPv6 connection table; PEB walk via NtQueryInformationProcess for CWD. 64-bit only. |
Walking parents stops at common interactive shells (bash, zsh, fish, sh, dash, ksh, tcsh, csh) so the proxy never hijacks a shellβs CWD.
The PID β {cwd, git-remote} cache uses a sync.Map with a TTL (default 60 s). On every Get, the caller re-reads the current CWD and the cache entry is dropped on mismatch β this guards against PID recycling.
A background sweep every 5 minutes drops expired entries and entries whose PID is no longer alive (kill -0).
The git remote -v shell-out has a hard 2 s timeout. On timeout or no remote, the request is forwarded without the X-Git-Remote header rather than blocking.
Streaming
Section titled βStreamingβThe proxy uses httputil.ReverseProxy with FlushInterval=-1, which forces a flush per write. SSE / chunked responses reach the client as the upstream emits them β no body buffering. Client disconnect cancels the upstream context.
Health endpoint
Section titled βHealth endpointβGET /_proxy/healthzReturns version, commit, uptime, and (when wired) cache stats.
{ "status": "ok", "version": "v0.1.0", "commit": "abc1234", "uptime": "1h23m", "cache": { "entries": 12, "hits": 480, "misses": 64, "hit_rate": 0.882 }}