Skip to content

Latest commit

 

History

History
207 lines (149 loc) · 9.22 KB

File metadata and controls

207 lines (149 loc) · 9.22 KB

context-tracker

CI npm license

Language: English · 简体中文

Mirror the HTTP requests that AI coding CLIs (OpenCode / Claude Code / Codex) send to model providers into a local viewer, so you can inspect the full request context — headers, system prompt, tool definitions, messages — and (optionally) the model's response.

Architecture

Claude Code ──ANTHROPIC_BASE_URL──▶ ┐
Codex CLI  ──config.toml base_url─▶ ├─▶ proxy ──HTTPS──▶ AI API
OpenCode   ──opencode.json baseURL▶ ┘      │
                                            └──POST──▶ viewer (:39877)

The proxy forwards traffic untouched to the upstream API and mirrors a copy of each request to the viewer — a fire-and-forget side channel that never blocks or alters the main request/response path. One proxy port can route to multiple upstreams by path prefix; the viewer classifies entries by source and API protocol.

Install

Requires Node.js >= 18. Zero runtime dependencies.

Global install (recommended):

npm install -g context-tracker
# or from source: git clone https://github.com/conrad621/context-tracker.git && cd context-tracker && npm link

This provides a single context-tracker command with proxy / viewer subcommands:

context-tracker help            # show usage
context-tracker viewer          # start the viewer
context-tracker proxy anthropic # start the proxy with a profile

Without installing you can run the scripts directly: node src/viewer.js, node src/proxy.js <profile>. Both forms are interchangeable below.

Usage

1. Start the viewer

context-tracker viewer          # or: node src/viewer.js

The viewer prints each request live in the terminal (with a model / system / tools / messages summary) and serves a web UI at http://localhost:39877.

Set REDACT_AUTH=1 to automatically redact API keys:

REDACT_AUTH=1 context-tracker viewer

2. Start the proxy

Recommended: start with a profile (no need to type TARGET_URL)

profiles.json ships with common providers preconfigured — start one by name:

context-tracker proxy anthropic     # loads the "anthropic" profile from profiles.json
context-tracker proxy openai
context-tracker proxy claude+codex  # multi-upstream routing profile

context-tracker proxy               # no argument: interactively pick a profile

Environment variables always override profile values (e.g. PROXY_PORT=9000 context-tracker proxy anthropic).

profiles.json format:

{
  "anthropic": {
    "target": "https://api.anthropic.com",  // single upstream
    "source": "claude-code",                 // mirror source label (defaults to the profile name)
    "captureResponse": true                  // optional: capture responses too
  },
  "claude+codex": {
    "routes": [                              // multi-upstream routing by path prefix (instead of target)
      {"prefix":"/v1/messages","target":"https://api.anthropic.com","source":"claude-code"},
      {"prefix":"/v1/responses","target":"https://api.openai.com","source":"codex"}
    ],
    "captureResponse": true
  }
}

Available profile fields: target, routes, source, port, mirrorPort, captureResponse, maxResponseBytes, redactAuth.

Manual mode (without a profile)

# single upstream
TARGET_URL=https://api.deepseek.com node src/proxy.js

# multi-upstream routing (capture Claude + Codex on one port)
ROUTES='[
  {"prefix":"/v1/messages","target":"https://api.anthropic.com","source":"claude-code"},
  {"prefix":"/v1/responses","target":"https://api.openai.com","source":"codex"}
]' node src/proxy.js

3. Point each tool at the proxy

Claude Code (calls POST /v1/messages):

export ANTHROPIC_BASE_URL=http://localhost:39876
export ANTHROPIC_API_KEY=sk-ant-...        # or ANTHROPIC_AUTH_TOKEN
claude

Codex CLI (calls POST /v1/responses) — edit ~/.codex/config.toml:

model_provider = "capture"

[model_providers.capture]
name = "Capture Proxy"
base_url = "http://localhost:39876/v1"      # client sends /v1/responses
env_key = "OPENAI_API_KEY"
wire_api = "responses"
export OPENAI_API_KEY=sk-...
codex

Codex defaults to ChatGPT subscription login; to capture traffic you must use API-key auth (the env_key above).

OpenCode — set the provider's baseURL to http://localhost:39876 in opencode.json.

⚠️ The /v1 path prefix: Claude Code and Codex send the full path including /v1 themselves, so TARGET_URL / route target must be the host root (e.g. https://api.anthropic.com, without /v1) — otherwise you get a doubled /v1/v1/... prefix. If OpenCode only sends /messages, then TARGET_URL needs to include /v1.

4. Start chatting

Request context appears live in both the viewer terminal and the web UI. Each entry offers structured / raw / headers / (optional) response views.

Web UI features:

  • Search — the top search box filters by path / model / content in real time, with match highlighting (/ to focus, Esc to clear)
  • Filter — source / api chips, multi-select and stackable
  • Live metrics — total requests, currently shown, requests per minute
  • Pause / follow / clearpause freezes live updates, follow auto-scrolls to newest, clear empties the view
  • Text selection — hover any content box for select-all / copy; double-click selects the whole block
  • Incremental sync — the client only fetches new/updated entries (/__history?since=), so poll cost stays flat regardless of history size
  • Virtual scrolling — only viewport rows are rendered; thousands of requests still mean only a few dozen DOM nodes
  • Stable expansion — an expanded entry stays open and keeps its active tab across live refreshes
  • Response usage — when response capture is on, the response pane parses the SSE stream into a token-usage / stop-reason / tool-call summary
  • Request diff — a "diff" view compares each request against the previous one from the same source: system-prompt changes, added/removed/changed tools, added/removed message turns
  • Token accounting & composition — each request shows a token count (real usage when captured, else estimated) and a stacked bar breaking it into system / tools / history / current, with per-tool cost
  • Cost stats — a Stats panel aggregates captured traffic by model and source (requests, tokens, estimated USD cost); prices are configurable in config/pricing.json
  • Waste detection — requests are flagged for oversized system prompts, large/duplicated tool schemas, over-long history, and repeated messages, with a suggestions list
  • Session filter — requests carrying a session id (from headers or body) can be isolated to view one agent task's turns as a timeline
  • Export — export the current view, a single request, or a session to JSON / Markdown / HAR (via export links or the /__export endpoint)

Environment variables

Variable Default Description
PROFILES ./config/profiles.json path to the profile config file
PROXY_PORT 39876 proxy listen port
MIRROR_PORT 39877 viewer listen port
TARGET_URL - single upstream base URL; used with or as the fallback for ROUTES
ROUTES - JSON array routing by prefix to different targets, with an optional source label
SOURCE - manual source label in single-upstream mode
CAPTURE_RESPONSE - when 1, tee and aggregate the SSE response and associate it with its request
MAX_RESPONSE_BYTES 2097152 response aggregation cap (truncated beyond this)
MAX_HISTORY 2000 max number of requests the viewer retains
REDACT_AUTH - when 1, redact API keys (applied at viewer render time)

Testing

npm test        # runs: node --test

Includes protocol-extraction unit tests (Anthropic Messages / OpenAI Chat / OpenAI Responses), config/profile-loading unit tests, and end-to-end tests (mock SSE upstream + proxy + viewer) verifying routing, streaming passthrough, mirror classification, redaction, response aggregation, and profile startup.

Supported protocols

API Path Source tool
Anthropic Messages /v1/messages Claude Code
OpenAI Responses /v1/responses Codex
OpenAI Chat Completions /v1/chat/completions OpenCode / DeepSeek / etc.

Limitations

  • Only works with header-authenticated providers (Anthropic, OpenAI, DeepSeek, OpenRouter, etc.). Signature-based auth such as AWS Bedrock (SigV4) or Google Vertex is not supported.
  • Codex subscription login (ChatGPT) cannot be captured; switch to API-key auth.
  • Response capture has a memory cost, bounded by MAX_RESPONSE_BYTES; oversized responses keep only a truncated copy.

Roadmap

Where the project is headed — see ROADMAP.md.

License

MIT