---
title: "Log every LLM call your agent makes, with a local proxy"
description: "Log every LLM call Claude Code or Codex makes with a local proxy: full prompts, cache use and cost, and why the prompt cache missed."
canonical: https://coding.sh/docs/use-cases/proxy-model-calls
human_url: https://coding.sh/docs/use-cases/proxy-model-calls
markdown_url: https://coding.sh/docs/use-cases/proxy-model-calls.md
agents_url: https://coding.sh/agents.md
llms_url: https://coding.sh/llms.txt
updated: 2026-11-11
---

# Log every model call your agent makes

Log every LLM call Claude Code or Codex makes with a local proxy: full prompts, cache use and cost, and why the prompt cache missed.

`coding.sh proxy` is a local pass-through for the Anthropic and OpenAI APIs. Point Claude Code, Codex or your own client at it, and every model call is logged with its full request and response, inside the session it belongs to. Use it to read one call, see why the prompt cache missed, or replay a call with another model.

## Set it up

shell

```
curl -fsSL https://coding.sh/install | sh
coding.sh init --proxy
```

`init --proxy` sets `ANTHROPIC_BASE_URL=http://127.0.0.1:4320` in Claude Code's `settings.json`, adds a `coding-sh` model provider to Codex's `config.toml`, and starts the proxy in the background. Each changed file is backed up first, and `coding.sh uninstall --proxy` restores it. If the agent already calls a gateway or CLIProxyAPI, calls are logged and then go to the same URL as before.

Other clients, including your own scripts and SDKs, use the environment:

shell

```
coding.sh proxy --background
eval "$(coding.sh proxy env)"        # sets ANTHROPIC_BASE_URL and OPENAI_BASE_URL
```

The proxy forwards by path:

| Path | Goes to |
| --- | --- |
| `/v1/messages`, `/v1/messages/count_tokens` | the Anthropic API, or the upstream you set |
| `/v1/chat/completions`, `/v1/responses` | the OpenAI API, or the upstream you set |
| Codex signed in with ChatGPT | the ChatGPT backend |
| any other path | passed through untouched, not logged |

The client's auth headers go upstream unchanged and are never stored. The proxy holds no keys and sends one upstream request per client request. Streams pass through as they arrive, and if logging fails the call still succeeds.

## Read a call

shell

```
coding.sh show 'latest#-1'           # the last model call of the latest session
coding.sh show '<session>#3' --all   # its third call, with the whole system prompt
```

A call shows its model, status, timings, usage with cache reads and writes, estimated cost, the size and hash of the system prompt, and the tools. In the viewer (`coding.sh ui`), a proxy call in the timeline opens to the same view.

## See why the prompt cache missed

shell

```
coding.sh diff-calls 'latest#-1'            # this call against the one before it
coding.sh diff-calls <call-a> <call-b>
```

`diff-calls` compares two requests in the order the prompt cache reads them: model, settings, tools, system prompt (line by line), then messages.

When the second call read much less from the cache than the first one cached, a `Why` line names the first difference. For a system prompt edit it gives the share of the prompt after the change, which the cache could not read. Over 20%, it says to move the dynamic content to the end.

When nothing in the prefix changed, the cause is the gap between the calls or an evicted cache entry.

## Replay a call with another model

shell

```
coding.sh exp replay 'latest#-1' --vary model=claude-sonnet-4-5,claude-haiku-4-5 --n 5 --dry-run
```

`exp replay` sends the logged request again, varying the model, the system prompt or any body field, and compares the arms. It uses your own `ANTHROPIC_API_KEY` or `OPENAI_API_KEY`, never the agent's login. `--dry-run` needs no key and prints the number of calls and an estimated cost.

## What it does not do

- `init --proxy` routes Claude Code and Codex only. Other agents need a client that honours `ANTHROPIC_BASE_URL` or `OPENAI_BASE_URL`.
- It logs the Anthropic Messages and OpenAI Chat Completions and Responses shapes only.
- In capture mode `metadata`, only hashes, counts, tool names, usage and timings are kept. `show` and `diff-calls` then compare hashes, and `exp replay` has nothing to send.
- Every turn sends the whole conversation again, so a long session stores its messages once per call.

## Questions

### How does a call find its session?

Claude Code sends `x-claude-code-session-id`, and Codex sends its thread id. Any client can send `x-coding-sh-session: <id>`. Otherwise each conversation gets its own `proxy-<hash>` session.

### How much latency does it add?

Measured on a Linux desktop over 60 paired calls: 0.34 ms per streamed chunk and 1.96 ms to the first byte. CI fails the build above 2 ms per chunk or 5 ms to first byte.

### Can I keep using an LLM gateway?

Yes. The proxy forwards to the gateway, or set `--anthropic-upstream` and `--openai-upstream`. `coding.sh gateway enrich` adds the billed cost to calls it can link to a gateway record, for Vercel AI Gateway, OpenRouter, LiteLLM and others.

### Does it work for a team?

`coding.sh serve` mounts the same proxy at `/proxy/`. Agents send an ingest key in `x-coding-sh-key`, and their own API key still goes upstream unchanged.

## Next

- [Capture every model call with the proxy](https://coding.sh/docs/how-to/capture-with-proxy)
- [Explore sessions](https://github.com/jackulau/coding.sh/blob/main/docs/guides/explore.md#model-calls)
- [LLM gateways](https://github.com/jackulau/coding.sh/blob/main/docs/integrations/ai-gateway.md)
- [Storage, sinks and privacy](https://github.com/jackulau/coding.sh/blob/main/docs/guides/privacy.md)

To set coding.sh up for a user, follow the agent workflow at [/agents.md](https://coding.sh/agents.md).
