Summary
Piping output to stdout doesn't work, for two independent reasons:
-o /dev/stdout hangs forever. Confirmed: the command never produces output and has to be killed.
- Progress/status text is written to stdout, not stderr, so even if (1) were fixed, the content stream would be polluted with lines like
Processing …, Loading … from cache, and Successfully converted ….
Together these block the natural workflow of claude-code-log … -o - | sed 's/^/> /' | <clipboard>, forcing a write-to-temp-file-then-cat detour.
Repro (v1.4.0)
# (1) hangs
claude-code-log session.jsonl -f markdown -o /dev/stdout # never returns
# (2) status text on stdout
claude-code-log session.jsonl -f markdown -o out.md # "Processing…"/"Successfully…" go to stdout
Cause
- Hang: before writing, the code runs a staleness check
renderer.is_outdated(output_path) (converter.py:1728). For /dev/stdout the path "exists", so is_outdated opens it read-only to sniff the version marker (markdown/renderer.py:2174). When stdout is a pipe, /dev/stdout resolves to the pipe's write end; opening it O_RDONLY and calling readline() blocks waiting for bytes that never come → deadlock. (Fixing the "existing -o file skips regeneration" issue — bypassing the staleness skip for explicit -o — would also resolve this, since is_outdated would no longer be called.) A Path.is_file() guard in is_outdated would harden it regardless.
- stdout noise: status output uses bare
print(...) (converter.py:252, :270, etc.) and click.echo(...) without err=True (cli.py:1128, the per-project summaries, etc.). Only warnings pass err=True.
Suggested fix
- Treat
-o - (and /dev/stdout) as "stream to stdout, always regenerate, don't consult or write cache, don't open a browser."
- Route all progress/status/summary output to stderr (sweep
click.echo(..., err=True) and replace the bare prints with logging/stderr), so stdout carries only the rendered document.
Investigation and write-up by Claude (Claude Code).
Summary
Piping output to stdout doesn't work, for two independent reasons:
-o /dev/stdouthangs forever. Confirmed: the command never produces output and has to be killed.Processing …,Loading … from cache, andSuccessfully converted ….Together these block the natural workflow of
claude-code-log … -o - | sed 's/^/> /' | <clipboard>, forcing a write-to-temp-file-then-catdetour.Repro (v1.4.0)
Cause
renderer.is_outdated(output_path)(converter.py:1728). For/dev/stdoutthe path "exists", sois_outdatedopens it read-only to sniff the version marker (markdown/renderer.py:2174). When stdout is a pipe,/dev/stdoutresolves to the pipe's write end; opening itO_RDONLYand callingreadline()blocks waiting for bytes that never come → deadlock. (Fixing the "existing-ofile skips regeneration" issue — bypassing the staleness skip for explicit-o— would also resolve this, sinceis_outdatedwould no longer be called.) APath.is_file()guard inis_outdatedwould harden it regardless.print(...)(converter.py:252,:270, etc.) andclick.echo(...)withouterr=True(cli.py:1128, the per-project summaries, etc.). Only warnings passerr=True.Suggested fix
-o -(and/dev/stdout) as "stream to stdout, always regenerate, don't consult or write cache, don't open a browser."click.echo(..., err=True)and replace the bareprints with logging/stderr), so stdout carries only the rendered document.Investigation and write-up by Claude (Claude Code).