Documentation
¶
Overview ¶
Package tap is a local reverse proxy that records the requests AI coding CLIs (Claude Code, Codex, Gemini CLI, Grok) send to their model providers.
Each CLI is pointed at the proxy through its own base URL environment variable, so no CA certificate is needed: the CLI talks plain HTTP to 127.0.0.1 and the proxy talks HTTPS to the real provider.
Index ¶
- Constants
- Variables
- func CLINames() []string
- func Redact(x *Exchange, secrets []string)
- func WriteBodies(w io.Writer, x *Exchange) error
- func WriteEnv(w io.Writer, shell, base string, clis []CLI) error
- func WriteLine(w io.Writer, x *Exchange) error
- type Binding
- type Body
- type CLI
- type Event
- type Exchange
- type Info
- type Options
- type Proxy
- type Redaction
- type Route
Constants ¶
const ( PingPath = "/_acurl/ping" // GET: Info, so wrappers and viewers can tell the proxy is up EventsPath = "/_acurl/events" // GET: a JSON line per Event until the proxy stops StopPath = "/_acurl/stop" // POST: stop the proxy )
Control endpoints served next to the provider routes.
const DefaultMaxBody = 1 << 20
DefaultMaxBody is how much of each body a capture keeps.
const Redacted = "[redacted]"
Redacted replaces every removed value.
Variables ¶
var CLIs = []CLI{ { Name: "claude", Bindings: []Binding{{Env: "ANTHROPIC_BASE_URL", Route: "anthropic"}}, Note: "API key and claude.ai login both work", }, { Name: "codex", Bindings: []Binding{{Env: "OPENAI_BASE_URL", Route: "openai", Suffix: "/v1"}}, Note: "API key login only; ChatGPT login talks to chatgpt.com and bypasses the base URL", }, { Name: "gemini", Bindings: []Binding{ {Env: "GOOGLE_GEMINI_BASE_URL", Route: "gemini"}, {Env: "CODE_ASSIST_ENDPOINT", Route: "code-assist"}, }, Note: "Gemini API key and Google login; Vertex AI is not routed", }, { Name: "grok", Bindings: []Binding{{Env: "GROK_CLI_CHAT_PROXY_BASE_URL", Route: "grok", Suffix: "/v1"}}, Note: "Grok Build CLI with grok.com login", }, }
CLIs are the tools `acurl tap env` writes wrappers for.
var DefaultRoutes = []Route{
{Name: "anthropic", Prefix: "/anthropic", Upstream: "https://api.anthropic.com"},
{Name: "openai", Prefix: "/openai", Upstream: "https://api.openai.com"},
{Name: "gemini", Prefix: "/gemini", Upstream: "https://generativelanguage.googleapis.com"},
{Name: "code-assist", Prefix: "/code-assist", Upstream: "https://cloudcode-pa.googleapis.com"},
{Name: "grok", Prefix: "/grok", Upstream: "https://cli-chat-proxy.grok.com"},
}
DefaultRoutes are the provider APIs the proxy forwards to.
var Shells = []string{"bash", "zsh", "fish", "powershell"}
Shells that `acurl tap env` can write wrappers for.
Functions ¶
func Redact ¶
Redact replaces each of secrets in x's headers, URL and bodies, and records where it did.
func WriteBodies ¶
WriteBodies writes the request and response bodies of x under a header line, for `acurl tap --bodies`.
func WriteEnv ¶
WriteEnv writes shell functions that run each CLI through the proxy at base (e.g. "http://127.0.0.1:8899") while `acurl tap` is running, and straight to the provider when it is not, so the CLI never breaks.
Types ¶
type Binding ¶
type Binding struct {
Env string // e.g. "ANTHROPIC_BASE_URL"
Route string // Route.Name
Suffix string // appended to the route URL, e.g. "/v1" for OpenAI-style bases
}
Binding is one environment variable that points a CLI at a route.
type Body ¶
type Body struct {
Text string `json:"text,omitempty"`
Size int64 `json:"size"`
Encoding string `json:"encoding,omitempty"`
Truncated bool `json:"truncated,omitempty"`
}
Body is a captured message body. Text holds at most the proxy's body limit, decoded when the body had a Content-Encoding; Size is the length that passed through on the wire.
type CLI ¶
type CLI struct {
Name string // the command, e.g. "claude"
Bindings []Binding
Note string // limits worth knowing, shown by `acurl tap env --list`
}
CLI is an AI command line tool acurl knows how to tap.
type Event ¶
type Event struct {
Exchange *Exchange `json:"exchange,omitempty"`
// Dropped counts exchanges this viewer missed because it read too slowly.
Dropped int64 `json:"dropped,omitempty"`
}
Event is one line of the events stream.
type Exchange ¶
type Exchange struct {
ID int64 `json:"id"`
Start time.Time `json:"start"`
Duration time.Duration `json:"duration_ns"`
Route string `json:"route"`
Method string `json:"method"`
URL string `json:"url"`
Model string `json:"model,omitempty"`
ReqHeader http.Header `json:"request_headers"`
ReqBody Body `json:"request_body"`
Status int `json:"status,omitempty"`
RespHeader http.Header `json:"response_headers,omitempty"`
RespBody Body `json:"response_body"`
Streaming bool `json:"streaming,omitempty"`
Upgrade string `json:"upgrade,omitempty"` // e.g. "websocket"; frames are not recorded
Err string `json:"error,omitempty"`
Canceled bool `json:"canceled,omitempty"` // the CLI hung up before the response ended
Redactions []Redaction `json:"redactions,omitempty"`
}
Exchange is one request a CLI made through the proxy and the response it got.
type Info ¶
type Info struct {
Name string `json:"name"` // always "acurl tap"
Version string `json:"version"`
PID int `json:"pid"`
MaxBody int `json:"max_body"`
KeepCredentials bool `json:"keep_credentials"`
Viewers int `json:"viewers"`
}
Info describes a running proxy.
type Options ¶
type Options struct {
Routes []Route // DefaultRoutes when empty
MaxBody int // DefaultMaxBody when zero
// KeepCredentials leaves API keys, tokens and cookies in captures.
KeepCredentials bool
// Secrets are extra strings removed from headers, URLs and bodies.
Secrets []string
// OnExchange receives every finished exchange, as do viewers connected
// to EventsPath. It is called from many goroutines at once.
OnExchange func(*Exchange)
// OnStop is called when a client asks the proxy to stop through
// StopPath. Without it, StopPath is refused.
OnStop func()
// Version is reported by PingPath.
Version string
// Transport sends requests upstream; a clone of http.DefaultTransport
// when nil.
Transport http.RoundTripper
}
Options configures a Proxy.
type Proxy ¶
type Proxy struct {
// contains filtered or unexported fields
}
Proxy forwards CLI requests to their providers and records each exchange.