prompttap
v0.3.0
Published
Inspect the model API traffic sent by Claude Code and Codex through a local proxy and dashboard.
Downloads
472
Maintainers
Readme
PromptTap
See what Claude Code and Codex send to their model APIs: instructions and system prompts, tools, message history, streamed output, tool calls, reasoning summaries, token usage, and the fields PromptTap does not model yet.
PromptTap is a local wrapper. It starts a reverse proxy and dashboard, prepares routing for the selected CLI, launches that CLI in your project, and shuts the proxy down when the child exits. Captured traffic stays in memory and is sent only to the upstream API or gateway you selected.
Why this exists
Coding agents assemble large requests on your behalf. The terminal usually shows the final interaction, not the exact API payload, so questions such as these are hard to answer:
- Which instructions, tools, schemas, and conversation items were sent?
- What changed since the previous turn?
- Did a skill, MCP server, hook, or project instruction affect the request?
- How were streamed text, reasoning summaries, and tool arguments returned?
Most request content is repeated between turns, so PromptTap opens on a diff against the previous request with the same client/session key. Codex traffic without a stable session header is compared with the previous Codex request, never with Claude traffic.
Requirements
- Node.js 20.19+ (20.x) or 22.12+; Vite 8 does not support Node 21 or earlier Node 22 releases.
claudeonPATHfor Claude mode.codexonPATHfor Codex mode.- Credentials already configured for the selected CLI or upstream gateway.
Claude Code through Amazon Bedrock, Google Vertex AI, or Microsoft Foundry is
not supported because those paths do not use ANTHROPIC_BASE_URL.
Usage
Bare prompttap is the short form for Claude Code:
cd /path/to/project
npx prompttapSelect a client explicitly and place that client's arguments after --:
npx prompttap claude -- --model sonnet
npx prompttap codex -- --model gpt-5
npx prompttap codex -- exec "explain this repository"PromptTap options go before the client name:
npx prompttap [options] [claude] [-- <claude args>]
npx prompttap [options] codex [-- <codex args>]
-p, --port <n> Proxy/dashboard port (default: 8080)
-C, --project <dir> Project and child working directory
--upstream <url> Override the detected/default upstream
-y, --yes Accept the Claude gitignore prompt in non-TTY use
-o, --open Open the dashboard in a browser
-h, --help Show helpThe startup output shows the selected client, upstream, and dashboard URL. The child inherits the current environment and terminal stdio. Its exit code is propagated by PromptTap.
Claude routing
Claude mode binds the proxy first, then temporarily writes
env.ANTHROPIC_BASE_URL to the project's
.claude/settings.local.json, and only then launches claude. PromptTap backs
up the complete original file before writing and restores it after the child
exits or PromptTap receives SIGINT, SIGTERM, or SIGHUP.
If the local settings file is tracked, PromptTap asks before adding
.claude/settings.local.json to .gitignore. Existing Anthropic gateways are
detected and remain the upstream. A stale patch from a crashed run is healed on
the next Claude-mode launch.
Codex routing
Codex mode appends these invocation-only CLI overrides before spawning
codex:
-c openai_base_url="http://127.0.0.1:<port>/v1"
-c 'model_providers.prompttap_http={ ..., requires_openai_auth = true, supports_websockets = false }'
-c model_provider="prompttap_http"
-c features.enable_request_compression=falseThe PromptTap overrides are appended after user arguments so capture stays
authoritative. The invocation-only provider preserves OpenAI API-key or ChatGPT
authentication but declares the PromptTap hop HTTP/SSE-only, so Codex does not
attempt a Responses WebSocket before falling back to HTTP. Request compression
is disabled only for the launched child: current Codex versions otherwise
zstd-compress Responses request bodies, which Node 20 cannot decode without a
runtime dependency. The upstream response is still streamed normally.
PromptTap does not read or modify
~/.codex/config.toml or a project-local .codex/config.toml. It also skips
all Claude settings and gitignore logic in Codex mode.
Codex can authenticate either with an OpenAI API key or a ChatGPT account.
Without --upstream, PromptTap selects the matching first-party target per
request: https://api.openai.com/v1 for API-key traffic and
https://chatgpt.com/backend-api/codex for ChatGPT traffic. The local /v1
facade is removed when forwarding to the ChatGPT backend. This keeps the
invocation-only override compatible with both login methods.
Dashboard
Requests appear live with a compact Claude/Codex label and are grouped by their client/session key.
| Tab | What it shows | | --- | --- | | Diff | Changes from the previous request for the same client/session key. | | System | Anthropic system blocks and OpenAI instructions/system/developer blocks. | | Tools | Tool names, parameters, and descriptions. | | Messages | Text, images, tool calls, and tool outputs sent as input. | | Response | Reconstructed text, reasoning summaries, tool calls, errors, and usage. | | Metadata | Client, API family, path, timing, redacted headers, beta flags when present, and unmodeled request fields. |
PromptTap classifies /v1/messages as Anthropic Messages traffic and
/v1/responses as OpenAI Responses traffic. Other supported /v1/* and
/api/* paths are forwarded and retained with an unknown API family.
Upstream gateways
Use --upstream to forward through a gateway:
npx prompttap --upstream https://gateway.example/v1 codex -- exec "inspect this project"A trailing /v1 is normalized against client paths, so PromptTap does not
forward to /v1/v1/responses. Request credentials are relayed upstream
unchanged. Passing --upstream disables the first-party auth-aware selection;
all selected-client traffic is sent to that gateway.
Privacy and safety
- PromptTap listens only on
127.0.0.1; dashboard/static routes also validate the localhostHostheader to resist DNS rebinding. authorization, API keys, ChatGPT/OpenAI account IDs, proxy credentials, cookies, and set-cookie values are forwarded when needed but redacted before storage or display.- Captured exchanges stay in memory only, with a 500-exchange cap, and vanish when PromptTap exits.
- Prompt and source content is intentionally visible in the dashboard. Treat dashboard screenshots like editor screenshots.
- The runtime uses Node built-ins only; coverage tooling is development-only.
Troubleshooting
claude or codex was not found on PATH. Install the selected CLI or
fix PATH, then rerun the same wrapper command. PromptTap tears down the proxy
and restores Claude settings when spawning fails.
Port 8080 is already in use. Stop the other process or choose a port with
--port. PromptTap binds before any Claude settings mutation, so a bind failure
leaves settings untouched.
The dashboard is empty. Confirm the selected child is still running and
that its API traffic uses Anthropic Messages or OpenAI Responses. For a custom
gateway, pass its base URL with --upstream.
Codex reports Unauthorized or only error. Update PromptTap to a version
with auth-aware Codex routing. API-key and ChatGPT logins use different
first-party upstreams; current PromptTap selects between them automatically.
The Response tab retains the upstream error detail when one is returned.
Claude Code fails to connect after an unclean shutdown. Run a Claude-mode
PromptTap command again to heal a stale patch, or restore/remove the
ANTHROPIC_BASE_URL entry in .claude/settings.local.json manually.
Codex config changed. PromptTap never writes Codex TOML files. Inspect other
tools or commands that ran in the project; PromptTap routing exists only in the
spawned process's -c openai_base_url=... arguments.
Development
The repository pins Node.js 24.18.0 for development through .nvmrc:
nvm install
nvm usenpm install
npm test
npm run typecheck
npm run build
npm run coverageCoverage thresholds are 80% for statements, branches, functions, and lines.
Fixtures are synthetic and use obvious _test_ identifiers; recorded traffic,
real credentials, and personal paths do not belong in the repository.
Publishing
Every push to main runs the test, type-check, and build steps, increments the
minor version, and publishes the package through npm Trusted Publishing (OIDC).
After publication, the workflow pushes the generated release commit and
v<version> tag. GitHub does not start another workflow for that commit because
it is pushed with the repository's GITHUB_TOKEN.
Configure the package's trusted publisher once on npmjs.com with these exact values:
- Provider: GitHub Actions
- Organization or user:
denisbalyko - Repository:
PromptTap - Workflow filename:
publish.yml - Allowed action:
npm publish
If prompttap has not been published before, publish the existing 0.1.0
version once to create the npm package, then configure the trusted publisher.
No NPM_TOKEN secret is required. The workflow needs permission to push its
release commit to main; account for that if branch protection or a repository
ruleset restricts direct pushes.
See ARCHITECTURE.md for lifecycle and routing decisions and CLAUDE.md for implementation constraints.
License
MIT
