Debugging
August 22, 2026 · View on GitHub
Wire trace
Set HAX_TRACE to capture HTTP requests, response statuses, and SSE events:
HAX_TRACE=/tmp/hax-trace.md hax
The trace is plain Markdown-like text and is truncated at startup. Credentials are redacted:
the standard auth headers by name, plus API keys and $VAR-resolved header values wherever
they appear.
Entries include elapsed-time tags so pauses between streamed chunks are visible. HAX_TRACE
records HTTP transport traffic, including provider requests, metadata probes, catalog refreshes,
and account-usage queries. It is silent for a mock-only run because no network is used.
Transcript log
Set HAX_TRANSCRIPT to mirror the same model-facing transcript available from Ctrl-T:
HAX_TRANSCRIPT=/tmp/hax-transcript.txt hax
The transcript includes the system prompt, advertised tools, user/assistant items, tool calls,
tool results, and reasoning items where present. The file is truncated at startup and on
/new, then appended as the conversation grows. It is useful when debugging prompt/context
behavior rather than raw HTTP.
Each turn ends with its usage line and, below it, what served the response:
1s · \$0.0003 · in 1.8k ~\$0.0003 · out 2
openrouter · openrouter/auto · high → deepseek/deepseek-v4 via Wafer
Provider, model, and reasoning effort are the values that turn ran under, spelled as the startup
banner spells them, so a /model or /effort switch is visible where it happened — an effort
change also explains a cache read dropping to zero on the line above. After the arrow is what
served the request: the model the response named when it differs from the one asked for, such as
an alias resolving to a dated snapshot, and the upstream endpoint a provider routed to.
Ctrl-T transcript view
In the REPL, press Ctrl-T to open the current transcript in $PAGER. This is an in-memory view
and does not require HAX_TRANSCRIPT.
Ctrl-O is its user-facing sibling: the same conversation as it was displayed (Markdown, tool previews, no system prompt or tool schemas). Reach for Ctrl-T when the question is what the model received, and Ctrl-O when it is what happened.
Mock provider
The mock provider exercises dispatch and rendering without an LLM:
HAX_PROVIDER=mock hax
HAX_PROVIDER=mock HAX_MOCK_SCRIPT=scripts/mock/demo.txt hax
Without a script, it parses the latest user message heuristically. For example, typing
run `ls -la` can trigger a real bash tool call.
With HAX_MOCK_SCRIPT, each provider stream() call consumes one scripted turn. Blank lines
and lines whose first non-whitespace character is # are ignored. The directives are:
text <message>
reasoning <message>
space
tool <name> <json>
delay <ms>
usage in=N out=M [cached=K] [cache_write=W] [cache_write_1h=H] [cost=D]
end-turn
text and reasoning decode \\n, \\t, and \\\\, then stream the result in small deltas;
reasoning is displayed only with HAX_SHOW_REASONING=1. space emits one single-space text
delta. delay sets the pacing for later text, reasoning, space, and tool emissions; zero restores
burst mode. tool takes a name and a single-line JSON object. usage sets the accounting on the
turn's final event, and end-turn completes the turn. A final turn may end at EOF.
{{CWD}} in text or tool arguments expands to the process working directory, allowing checked-in
fixtures to exercise path normalization without hard-coding a machine-specific path.
Mock-provider fixtures live under scripts/mock/:
| Fixture | Use |
|---|---|
demo.txt | End-to-end rendering and multi-turn tool dispatch. |
layout.txt | Header, gutter, and Markdown layout. |
diff.txt | Path normalization and diff rendering. |
pause.txt | Pauses between streamed events. |
tasks.txt | Background-task lifecycle. |
theme.txt | Semantic color roles. |
Mock runs leave nothing behind: no session file for /resume to list, and no prompts added
to Up/Ctrl-R recall, so driving the UI doesn't bury real conversations under fixtures. Pass
HAX_NO_SESSION=0 when the thing under test is the session or recall machinery.
Demo scripts
Useful executable helpers in scripts/:
| Script | Use |
|---|---|
stream_demo.py | Streaming patterns through the bash tool. |
mock_openai_server.py | Lightweight OpenAI-compatible test server. |
stream_demo.py modes include short, long, slow, burst, ansi, binary, piped,
and python_buffer.
Vision fixtures
scripts/vision_fixtures.py writes small deterministic PNGs (default
/tmp/hax-vision-fixtures) and prints, for each, the prompt to use and the expected answer —
ask the model to read one and check that the answer matches. Each fixture isolates one
question only the pixels can answer: a solid color to name (baseline pipeline check), a
red/blue layout to locate, dots to count, block text to transcribe. --edge adds oversized
fixtures the read tool must refuse (per-side pixel cap and byte cap), for exercising the
downscale-hint error path. docs/screenshot.png doubles as a realistic text-heavy fixture.
Capability detection can be pinned with HAX_IMAGE_INPUT=on|off (default auto: live
llama.cpp /props or OpenRouter /endpoints probe, then models.dev catalog modalities).
Wrong colors or counts indicate a pipeline bug; extra hallucinated detail on the layout
fixture is model quality, not plumbing.
Rendering and terminal knobs
HAX_MARKDOWN=0disables Markdown rendering.HAX_DISPLAY_WIDTH=<cols>forces a stable render width, useful for fixtures.HAX_SHOW_REASONING=1displays reasoning deltas when a provider emits them.HAX_NOTIFY=offdisables terminal/desktop completion notifications.
Provider startup checks
If the REPL starts with no provider selected, use /provider; unavailable rows show a reason.
For one-shot -p, provider construction failures are fatal.
Common checks:
- Codex: run
/login. If you instead borrow the official codex CLI login, make sure~/.codex/auth.jsonexists and refresh it by runningcodexagain when it expires. - OpenAI/OpenRouter/Anthropic/OpenCode: make sure the expected API key environment variable is
visible to the
haxprocess. openai-compatibleandanthropic-compatible: set the corresponding base URL.- llama.cpp/ollama: make sure the local server is reachable and the model is configured or discoverable.