Agent Context Probe is a local proxy and Dashboard for inspecting Anthropic Messages, OpenAI Chat Completions, and OpenAI Responses traffic. The production build is one Go executable: the React Dashboard is compiled as a SPA and embedded in the binary.
The default command is:
agent-context-probe startThe proxy, management API, health check, and Dashboard share
http://127.0.0.1:3001.
- Transparent Anthropic Messages, OpenAI Chat Completions, and OpenAI Responses proxying
- Streaming and non-streaming response capture
- First generated stream content timestamp and proxy-observed TTFT in request history
- SQLite request history with model, time, and header filters
- Session and parent/subagent trace views
- Agent framework integrations for Codex, OpenCode, Claude Code, LangChain/LangGraph, OpenAI Agents SDK, AutoGen, and CrewAI
- Normalized messages, reasoning, tool calls, tool results, token usage, and latency
- Grouped namespace tool definitions (including Codex MCP and multi-agent tools) with full parameter schemas
- Optional Claude Code subagent routing to different upstream models
- Optional downstream response fault injection for harness testing
- One executable with an embedded Dashboard; Node.js is not required at runtime
- Local-only listening by default
- Sensitive request and response headers redacted before SQLite persistence
- Explicit token authentication for non-loopback listening
Codex SDK requests (typically Originator: codex_sdk_ts) are grouped by
Thread-Id, so each agent retains its own model-call timeline even when parent
and child agents share Session-Id. X-Codex-Parent-Thread-Id links each child
to its direct parent, including nested subagents. Child threads without a
task tool-call association are displayed separately within the parent trace.
Identity headers are matched case-insensitively, using the first non-empty value
in this order: Thread-Id, X-Thread-Id, X-Session-Affinity,
X-OpenCode-Session, X-Claude-Code-Session-Id, Session-Id, X-Session-Id,
then X-Conversation-Id. Without any identity header, each
request remains separate. Shared Session-Id alone does not establish a direct
parent relationship; threads whose parent is absent from the captured history
are shown as roots. Existing stored headers are used when loading session views,
so previously captured requests benefit without a database migration.
History reconstructed from the first captured request preserves the original order of user prompts and tool calls. Consecutive user messages, such as Codex context followed by task instructions, are displayed together as one turn. Assistant messages and tool results separate genuine follow-up turns.
For streaming model responses, the stored response includes firstTokenAt
(RFC 3339 timestamp) and ttftMs (milliseconds from the proxy handler's request
start to the first completed SSE data line with generated text, reasoning, or
tool-call content). Metadata, usage, empty deltas, and terminal events do not
count. These fields are absent when no generated content is observed, including
non-streaming responses. The timing reflects arrival at this proxy, not delivery
to the client.
Building requires Go 1.21 or later and Node.js 20 or later. The resulting executable does not require Go, Node.js, npm, or a separate SQLite library.
git clone https://github.com/2proveit/agent-context-probe.git
cd agent-context-probe
make install
make build
./bin/agent-context-probe start./run.sh performs the build and start sequence as a convenience.
Run in PowerShell:
git clone https://github.com/2proveit/agent-context-probe.git
Set-Location agent-context-probe
powershell -NoProfile -ExecutionPolicy Bypass -File .\run.ps1The script builds bin\agent-context-probe.exe and starts the single process.
Release archives contain the executable, configuration example, README, LICENSE, and install/uninstall scripts. On macOS and Linux:
./scripts/install.sh --version 0.1.0-beta.1
export PATH="$HOME/.local/bin:$PATH" # if the installer reports it is missing
agent-context-probe versionOn Windows:
.\scripts\install.ps1 -Version 0.1.0-beta.1
agent-context-probe.exe versionRunning the installer again atomically replaces the executable and preserves configuration, request history, and backups. The uninstall scripts remove only the executable; user data is retained. The Windows installer adds its install directory to the user PATH and the Windows uninstaller removes that exact entry.
agent-context-probe start [--config FILE] [--data-dir DIR] [--host HOST] [--port PORT]
agent-context-probe doctor [--config FILE] [--data-dir DIR] [--host HOST] [--port PORT]
agent-context-probe version
Running the executable without a subcommand remains equivalent to start.
doctor validates the resolved configuration, embedded Dashboard, data
directory, database schema, and listen address without contacting an upstream
provider or modifying files. Run it while the service is stopped so it can test
the configured port.
| System | Configuration | Request database and backups |
|---|---|---|
| macOS | ~/Library/Application Support/Agent Context Probe/config.yaml |
~/Library/Application Support/Agent Context Probe/ |
| Linux | ${XDG_CONFIG_HOME:-~/.config}/agent-context-probe/config.yaml |
${XDG_DATA_HOME:-~/.local/share}/agent-context-probe/ |
| Windows | %APPDATA%\Agent Context Probe\config.yaml |
%LOCALAPPDATA%\Agent Context Probe\ |
No configuration file is created automatically. The data directory is created
on first start. The application no longer discovers .env, parent-directory
configuration files, or a current-directory requests.db; source checkouts can
keep the legacy layout by using ./run.sh, run.ps1, --config, --data-dir,
or DB_PATH explicitly.
Start Agent Context Probe, then open the Dashboard:
http://127.0.0.1:3001/
For Claude Code or another Anthropic-compatible client:
export ANTHROPIC_BASE_URL=http://127.0.0.1:3001
claudePowerShell equivalent:
$env:ANTHROPIC_BASE_URL = "http://127.0.0.1:3001"
claudeFor an OpenAI-compatible client, use this local API prefix:
http://127.0.0.1:3001/v1
Available endpoints:
POST /v1/messagesPOST /v1/chat/completionsPOST /v1/responsesGET /v1/models: requests with ananthropic-versionorx-api-keyheader forward toproviders.anthropic.base_url+/v1/models, preservingx-api-keyand filling in a missinganthropic-versionfrom configuration. Other requests (including Bearer-only requests) forward toproviders.openai.base_url+/models. If the selected provider has no custom base URL and the other provider does, the request falls back to the other provider. Empty base URLs and the built-in defaults (ignoring surrounding whitespace and trailing slashes) count as unconfigured; when both or neither are configured, header routing is retained. Both branches preserve the upstream status and body and capture the request/response for the dashboard. Upstream connection failures return 502.GET /healthGET /api/requestsDELETE /api/requestsGET /api/sessionsGET /api/ui-config
The removed /api/grade-prompt frontend route had no Go implementation and is
not part of the supported API.
The default host is 127.0.0.1. Cross-origin access is not enabled: the
Dashboard calls the Go API on the same origin.
The proxy forwards the original client credentials to the selected upstream,
subject to existing provider rules. A configured OPENAI_API_KEY replaces the
incoming OpenAI Authorization value for the upstream request. The stored copy
is separate: values for headers such as Authorization, Proxy-Authorization,
Cookie, Set-Cookie, and X-Api-Key are replaced with [REDACTED] before
being written to SQLite or returned by the management API. On startup, existing
rows are also migrated to remove those stored header values.
Selected configuration files, SQLite databases, and backups use mode 0600 on
Unix-like systems. Newly created data and backup directories use mode 0700.
Listening on 0.0.0.0, ::, or a LAN address requires an access token of at
least 16 characters. Configure it through ACP_ACCESS_TOKEN or
server.access_token:
ACP_HOST=0.0.0.0 \
ACP_ACCESS_TOKEN='replace-with-a-long-random-value' \
agent-context-probe startRemote API clients must send the token in
X-Agent-Context-Probe-Token. This control header is removed before proxying
and is never sent to an upstream provider. Browser users are redirected to
/auth; successful login creates an HttpOnly, SameSite=Strict session cookie.
Use a TLS reverse proxy when traffic crosses an untrusted network.
Copy config.yaml.example to config.yaml when file-based configuration is
needed:
server:
host: "127.0.0.1"
port: 3001
timeouts:
read: 15m
write: 15m
idle: 15m
providers:
anthropic:
base_url: "https://api.anthropic.com"
version: "2023-06-01"
max_retries: 3
openai:
base_url: "https://api.openai.com/v1"
# api_key: "prefer OPENAI_API_KEY"
storage:
# Omit db_path to use the operating system standard data directory.
# db_path: "/custom/path/requests.db"
# backup_dir: "/custom/path/backups"
max_capture_bytes: 10485760
web:
show_raw_stream_events: false
raw_request_max_display_chars: 0
raw_response_max_display_chars: 0Configuration value priority is command-line override, environment variable,
configuration file, then built-in default. Configuration file selection is
--config, then ACP_CONFIG, then the standard configuration path. Database
selection is --data-dir, then DB_PATH, then ACP_DATA_DIR, then
storage.db_path, then the standard data directory. Relative paths in YAML are
resolved from the selected configuration file directory.
Environment variables:
| Variable | Purpose |
|---|---|
ACP_CONFIG |
Explicit configuration file path |
ACP_DATA_DIR |
Data directory used when DB_PATH is unset |
ACP_HOST |
Listen host; defaults to 127.0.0.1 |
ACP_PORT |
Listen port; defaults to 3001 |
PORT |
Backward-compatible port alias |
ACP_ACCESS_TOKEN |
Required for non-loopback listening |
READ_TIMEOUT |
Go duration such as 30s or 15m |
WRITE_TIMEOUT |
Go duration |
IDLE_TIMEOUT |
Go duration |
ANTHROPIC_FORWARD_URL |
Anthropic upstream base URL |
ANTHROPIC_VERSION |
Anthropic API version |
ANTHROPIC_MAX_RETRIES |
Anthropic retry count |
OPENAI_BASE_URL |
OpenAI-compatible upstream API prefix |
OPENAI_API_KEY |
Optional upstream OpenAI key |
DB_PATH |
SQLite database path |
storage.max_capture_bytes limits retained OpenAI request and response bytes;
it does not truncate the proxied exchange. The raw display limits affect only
Dashboard rendering and not the stored value.
SQLite capture operations share one connection to serialize in-process writes. Each connection waits up to 3 seconds for an external database lock; a final capture failure is logged with the request ID. Large history reads or exports can delay queued captures. This does not change the configured database path, schema, or forwarded response bytes.
Optional response_corruption simulates malformed responses from self-hosted
models, inference frameworks, gateways, or middleware to test a harness's
validation, recovery, and fallback behavior. It supports all three generation
APIs (JSON and SSE), with faults such as empty output, repetition, invalid tool
calls, and stream truncation. Upstream requests are unchanged.
Disabled by default. Add this to your configuration and restart the proxy:
response_corruption:
enabled: true
every_n_requests: 1
seed: 42
modes: [empty_stop]empty_stop removes visible text and tool calls. every_n_requests: 1 selects
every eligible HTTP 200 generation response; set it to 3 for every third
eligible response. Upstream errors are excluded. Set enabled: false and restart
after testing.
SQLite stores provider responses before injection; inspect harness-side raw responses to see the injected faults. See the fault injection reference for all modes, selection rules, capture behavior, and validation steps, or config.yaml.example for the full configuration.
SQLite schema versions are recorded with PRAGMA user_version. A database
whose schema is newer than the executable is rejected to prevent downgrade
writes. When an existing database requires an upgrade, Agent Context Probe:
- removes persisted sensitive header values;
- creates a consistent SQLite backup under the configured backup directory;
- validates the backup with
PRAGMA quick_check; - applies all pending migrations in one transaction.
Backup files are never deleted automatically. doctor reports the current and
target schema without performing the migration.
Set model_mappings in config.yaml to replace exact incoming model names:
model_mappings:
claude-sonnet: deepseek-v4-flash
gpt-4o: custom-openai-modelMappings apply to Anthropic Messages, OpenAI Chat Completions, and OpenAI
Responses requests. The proxy changes only the upstream request's model
value; a model mapping never changes the selected provider. Ordinary Anthropic
requests use providers.anthropic.base_url; OpenAI requests use
providers.openai.base_url. Existing subagent routing may select a different
provider before the model mapping is applied. Mappings are exact and applied
once. Successful JSON and streaming responses report the client's original
model name, while request records retain both originalModel and
routedModel.
subagents:
enable: true
mappings:
code-reviewer: "gpt-4o"
deep-reasoning: "o3"Mappings are applied only when the matching Claude Code subagent definition is available. Unmapped models continue through the normal provider selection.
The runtime image contains one process and one exposed port. It has no Node.js
runtime or node_modules.
docker build -t agent-context-probe .
docker run --rm \
-p 3001:3001 \
-e ACP_ACCESS_TOKEN='replace-with-a-long-random-value' \
-v ./data:/app/data \
agent-context-probeThe container listens on 0.0.0.0, so the access token is mandatory. Open
http://127.0.0.1:3001/ and enter the same token. API clients must send the
control header described above. SQLite data is stored at
/app/data/requests.db by default.
The reusable agent-context-probe skill guides coding agents through proxy setup, session identity, API-based evidence collection, stream/tool-call diagnosis, and explicitly requested fault tests.
Point an agent at skills/agent-context-probe/SKILL.md, or copy the complete
skills/agent-context-probe/ folder into that agent's supported skill directory.
A repository-root skills/ folder is not automatically discovered by every agent.
For example: “Read /path/to/agent-context-probe/skills/agent-context-probe/SKILL.md
and use it to investigate my captured agent session.”
make install
make build # SPA build, asset synchronization, then Go build
make dev # build and start the single process
make run-proxy # build the SPA and run the Go process through go run
make run-web # optional Vite development server with /api proxying
make clean
make db-resetRelease validation:
goreleaser check
goreleaser release --snapshot --clean --skip=publishPushing a v* tag triggers .github/workflows/release.yml. The workflow builds
the tag artifacts once without publishing, tests those exact archives through
install/start/upgrade/uninstall without Go, Node.js, or npm in PATH, then
uploads the same files to the GitHub Release and publishes the linux/amd64
plus linux/arm64 GHCR image. Archives include SHA-256 checksums and SPDX JSON
SBOMs; GitHub generates provenance attestations for release artifacts and the
container image.
Validation commands:
cd proxy && go test ./...
cd ../web && npm run typecheck && npm test
cd ../web && npm run lint && npm run buildType checking, tests, lint, and the production SPA build are separate checks; run them independently when diagnosing an existing codebase violation.
agent-context-probe/
├── proxy/
│ ├── cmd/agent-context-probe/ # CLI entry point
│ └── internal/
│ ├── app/ # application composition and lifecycle
│ ├── buildinfo/ # injected version, commit, and build time
│ ├── capture/ # persistence redaction policy
│ ├── handler/ # protocol and management handlers
│ └── webui/ # embedded SPA and fallback handler
├── web/ # React/Vite SPA source
├── Dockerfile # single-process runtime image
├── Makefile
├── run.ps1
└── run.sh
Agent Context Probe was originally derived from seifghazi/claude-code-proxy and has since evolved into an independently maintained project.
We thank Seif Ghazi and the original contributors for their work. The original project and Agent Context Probe are distributed under the MIT License. See LICENSE for the applicable copyright and license notices.
MIT License. See LICENSE.
