Skip to content

Architecture

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/*

The order matters. Each layer runs in this order on the way in, reverse on the way out.

#MiddlewarePurpose
1recoveryLoggerPanic recovery; never echoes request headers.
2requestLoggerCompact structured log per request: method, path, status, latency, client_ip, has_auth/has_api_key booleans, has_query flag. Authorization values are never logged.
3MiddlewareGitRemoteResolves 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.
4ReverseProxy (NoRoute)Forwards to upstream 1:1, stamps User-Agent, streams SSE without buffering.

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.

OSImplementation
macOSlsof -iTCP:<port> -sTCP:ESTABLISHED -F pn (PID), lsof -p <pid> -d cwd -F n (CWD). 2 s exec timeout.
LinuxReads /proc/net/tcp[6] to map port β†’ inode, scans /proc/*/fd/ for the matching socket, then reads /proc/<pid>/cwd. Same-user only.
WindowsGetExtendedTcpTable 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.

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.

GET /_proxy/healthz

Returns 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 }
}