headforward documentation
headforward shrinks the tool output a coding agent reads (test runs, build logs, git output, JSON, file reads) before it reaches the model, so every turn costs fewer input tokens. It runs as a Claude Code hook, a local proxy, or both. Error lines are always kept, anything shortened can be read back, and your own messages are never changed.
Install
Requires Python 3.9 or newer on macOS, Linux or Windows. There are no other dependencies.
pip install headforward
Optional, for exact token counts instead of estimates:
pip install "headforward[exact]"
No pip? headforward is one file. Save headforward.py and run python3 headforward.py wherever these docs say headforward.
Quick start
- Turn on the hook for every Claude Code session, desktop app included:
headforward hooks install global
- Check your setup. It prints the fix for anything wrong:
headforward doctor
- Start a new Claude Code session and work as usual. When a noisy command is shortened, its output ends with a line like
[40 passing test lines omitted; full output: headforward show ID]. - See running totals any time:
headforward stats
Hooks (desktop app too)
A Claude Code PreToolUse hook pipes noisy commands through the filter. It runs inside every session, including Claude Code in the desktop app, which proxies can't reach.
headforward hooks install global # or one project: headforward hooks install ~/code/my-app headforward hooks uninstall global
| Commands | What happens |
|---|---|
Tests: pytest, npm test, go test, cargo test and similar | Passing-test lines collapse to a count. Failures, tracebacks and the summary are kept. |
Installs and builds: pip install, npm install, make, cargo build, docker build | Download, progress and build-step lines collapse to a count. |
git log | Hashes shortened, a single author stated once, stat bar graphs dropped. |
ls -l | Link counts dropped, a single owner stated once. |
grep, rg | Matches grouped under their file. |
log show and timestamped logs | Near-identical lines counted on the first one. |
Every other command is left alone. Error-like lines are always kept, the command's exit code is preserved, and the full output is saved: headforward show ID prints it, and --lines A-B prints part of it.
Always-on proxy (macOS)
Runs the proxy at login and points Claude Code's settings at it, so every terminal session is compressed without typing wrap.
headforward desktop on global # or one project: headforward desktop on ~/code/my-app headforward desktop status # running? which settings use it? where does it forward? headforward desktop off # stop it and undo every settings change
Settings change only after the proxy is confirmed running, and a backup is kept. If your settings already point ANTHROPIC_BASE_URL at another gateway (a router, cost tracker or company proxy), headforward goes in front of it: Claude Code → headforward → your gateway → Anthropic. desktop off puts your URL back.
Claude Code in the desktop app ignores ANTHROPIC_BASE_URL but honors HTTPS_PROXY. Add --https and headforward serves it as its HTTPS proxy:
headforward desktop on global --https
It makes a local certificate authority in ~/.headforward/ca that can only vouch for api.anthropic.com, and adds HTTPS_PROXY, NODE_EXTRA_CA_CERTS and NO_PROXY to the settings file. Only api.anthropic.com is decrypted; every other host gets a plain tunnel. There is no fallback: if the proxy is down, desktop sessions can't connect until it's back or you run desktop off.
An ANTHROPIC_BASE_URL exported in your shell overrides Claude Code settings and skips the proxy; headforward doctor warns about it.
Coding agents
wrap starts a private proxy on a random local port, launches the agent pointed at it, and shuts the proxy down when the agent exits.
| Agent | Command | Notes |
|---|---|---|
| Claude Code | headforward wrap claude | Sign in to Claude Code once with /login, or set ANTHROPIC_API_KEY. |
| OpenAI Codex CLI | headforward wrap codex | Use an API key login. A ChatGPT-account login talks to ChatGPT's servers and bypasses the proxy. |
| Aider | headforward wrap aider | Works with OpenAI and Anthropic models. |
Anything after the agent name is passed to the agent, for example headforward wrap claude --continue.
Proxy for your own app
Run the proxy, then point your SDK at it with its base URL setting.
headforward proxy --port 8787 # in your app's environment export ANTHROPIC_BASE_URL=http://127.0.0.1:8787 export OPENAI_BASE_URL=http://127.0.0.1:8787/v1
Supported request formats: Anthropic Messages, OpenAI Chat Completions and OpenAI Responses. Streaming responses pass through as they arrive.
If ANTHROPIC_BASE_URL or OPENAI_BASE_URL is already set when the proxy starts, it forwards there instead of the public API, so company gateways keep working. To force a destination, use --upstream URL.
Prompt compression
For text you paste into a chat app. It removes filler, greetings, sign-offs, wordy phrases and repeated sentences. Code is never rewritten.
# macOS: compress your clipboard and put it back pbpaste | headforward - -l high | pbcopy # a file headforward prompt.txt -l high
| Level | What it removes |
|---|---|
light | Extra spaces and blank lines. |
medium | Plus filler words, wordy phrases, greetings, sign-offs and repeated sentences. The default. |
high | Plus articles, hedges such as "I think", bold markers; JSON code blocks are minified. |
max | Plus comment-only lines and blank lines inside code blocks. |
To apply the tool-output rules to a file instead, use --tool: headforward api.json --tool.
Savings and billing
The proxy reads the usage numbers the provider returns with every response: input tokens, cache reads and output tokens. headforward stats shows those billed totals for the last 24 hours and all time, plus tokens saved. Savings are converted from characters removed at the token rate you were actually billed for those requests.
$ headforward stats Last 24 hours 212 requests 1,830,114 input tokens billed, ~402,770 saved (18% less input), cache hits 91%, 48,210 output
The numbers above are an illustration of the format, not a measurement.
Stats are stored locally in ~/.headforward/stats.jsonl.
Check answers don't change
Record real requests while you work, then replay each one to the model with and without compression and compare what comes back.
headforward wrap --record ~/lt-rec claude # work as usual headforward eval ~/lt-rec --tokens-only # exact token savings only headforward eval ~/lt-rec # also compare the model's answers
--tokens-onlyuses Anthropic's free token-counting endpoint, so it costs nothing on Anthropic recordings.- A full run makes two model calls per recording, capped at
--max-tokens(default 1024) each. - Answers are compared by the tool call the model chooses, or by text similarity when there is no tool call.
- Models are not perfectly repeatable. Run the same recordings with compression off to see your baseline rate of "different" answers.
- Requires
ANTHROPIC_API_KEYorOPENAI_API_KEY.
How compression works
headforward only rewrites tool results. System prompts and your messages reach the model unchanged.
| Input | What happens | Lossless? |
|---|---|---|
| JSON lists of same-shaped objects | Keys are written once and values as rows. A column with one value in every row is stated once. | Yes. The original can be rebuilt exactly. |
| A tool result identical to an earlier one | Replaced by [Same output as tool call X above.] | Yes. The earlier copy is still in context. |
| Logs and command output | Repeated lines collapse to one line with a count. Terminal color codes and trailing spaces are removed. | Yes, apart from color codes. |
| File reads | Line-number padding is trimmed. | Yes. |
Routine command output (hooks, --smart) | Runs of 3+ installs, progress bars, passing tests or build steps collapse to a count. | Recoverable with headforward show ID. |
Git log, ls -l, grep, timestamped logs (hooks, --lossy) | Repeated and derivable parts removed; every distinct line kept. | Recoverable with headforward show ID. |
Runs of near-identical log lines (--lossy only) | First and last lines kept, the middle replaced by a count. | No. |
Here is a JSON result before and after:
[{"id": 1, "status": "shipped", "total": 19.99},
{"id": 2, "status": "shipped", "total": 24.50},
{"id": 3, "status": "shipped", "total": 8.00}]
{"_cols":["id","total"],"_rows":[[1,19.99],[2,24.5],[3,8.0]],"_same":{"status":"shipped"}}
Prompt caching
Anthropic and OpenAI bill repeated prompt prefixes at a fraction of the normal rate. headforward is deterministic and never rewrites earlier turns, so each request still starts with exactly the bytes of the previous one and cache hits keep landing.
CLI reference
| Command | Options |
|---|---|
headforward wrap AGENT [args] | --lossy, --record FOLDER |
headforward proxy | --port N (default 8787), --upstream URL, --lossy, --record FOLDER |
headforward hooks install|uninstall [PROJECT|global] | none |
headforward desktop on|off|status [PROJECT|global] | --smart |
headforward doctor | none |
headforward show ID | --lines A-B |
headforward stats | none |
headforward eval FOLDER | --tokens-only, --limit N (default 50), --lossy, --max-tokens N |
headforward FILE (or - for stdin) | -l, --level light | medium | high | max; -t, --tool; --lossy; -s, --stats; -q, --quiet; --model NAME |
| Option | Meaning |
|---|---|
--lossy | Also shorten runs of near-identical log lines. |
--record FOLDER | Save each original request, without API keys, for eval. |
--upstream URL | Send all traffic to this base URL instead of the provider's API. |
-s, --stats | Print only the savings line. |
-q, --quiet | Don't print the savings line to stderr. |
--model NAME | Which tiktoken encoding to count with (default gpt-4o). |
Environment variables: HEADFORWARD_LOSSY=1 turns on lossy mode for wrap; HEADFORWARD_UPSTREAM sets the upstream for wrap.
Privacy and safety
- The proxy listens only on
127.0.0.1, so other machines can't reach it. - API keys and sign-in tokens pass straight through to the provider and are never stored.
--recordsaves request bodies, which contain your conversation, to the folder you choose. Authorization headers are removed. Delete the folder when you're done.- Stats contain only counts and timestamps.
Limits
- Savings depend on the work. JSON-heavy, log-heavy and repetitive sessions save the most. Sessions that mostly read new source code save little, because code is left as written.
- Browser chat apps (claude.ai, chatgpt.com) can't be proxied. Use prompt compression and paste.
- Codex signed in with a ChatGPT account bypasses the proxy. Use an API key.
- Claude Code in the desktop app ignores
ANTHROPIC_BASE_URL. Use hooks there, ordesktop on --https. - Conversation history usually costs more than tool output.
/clearbetween tasks and/compactin long sessions matter.
Troubleshooting
Claude Code says "Not logged in"
The terminal version of Claude Code has its own sign-in, separate from the desktop app. Type /login inside Claude Code once. headforward passes your sign-in through unchanged.
headforward: command not found
The folder pip installs scripts into isn't on your PATH. Run python3 -m pip show -f headforward to find it, or run the single file with python3 headforward.py.
No savings were recorded
Hooks and settings apply to new sessions only, so start a new Claude Code session. Then run something noisy, like your tests, and look for a headforward show ID line in the output. For the proxy, run headforward doctor: a shell ANTHROPIC_BASE_URL overrides Claude Code settings and skips it. Codex with a ChatGPT login and browser apps never reach the proxy.
A command with ! hangs at dquote>
In zsh, ! inside double quotes is history expansion. Press Ctrl-C, then use single quotes: echo 'Hello!' | headforward -.