Skip to content

fix(logs): declutter and clarify the readable session log - #21

Merged
c0d3ster merged 4 commits into
mainfrom
fix/readable-log-cleanup
Aug 6, 2026
Merged

fix(logs): declutter and clarify the readable session log#21
c0d3ster merged 4 commits into
mainfrom
fix/readable-log-cleanup

Conversation

@c0d3ster

@c0d3ster c0d3ster commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

  • Strips raw ANSI escape codes and stray \r bytes from tool output, fixing garbled colored text and phantom blank lines in the readable .log
  • Suppresses noise that's redundant with the request line or the eventual PR: Read results, pure file-inspection Bash chains (cat/ls/echo/head/tail/find/tasklist/ps), and git diff bodies
  • Condenses high-volume output into one-line or few-line summaries instead of raw dumps: Glob/Grep (and Bash-invoked grep) show match counts, git status --short shows a per-status-code count, git commit drops lefthook/commitlint decoration down to just the commit line + diffstat, vitest/tsc/eslint results extract just the failures/errors/summary, and bracketed-status tool output (codegen, dev-server startup) collapses to its final line
  • Aligns multi-line result bodies under the < prefix instead of falling back to column 0
  • overnight.sh now appends genuine tool/harness errors (is_error results) to the existing stderr log and deletes it if nothing landed there

Test plan

  • Regenerated all four logs/*.jsonl.log pairs after every change and diffed the output by hand against dozens of real examples (vitest failures, tsc/eslint errors, git add/commit/status/diff, Glob/Grep, dev server startup, chained Bash commands)
  • Verified no ANSI escape or \r bytes remain in any regenerated log
  • Confirmed suppression rules don't over-trigger (e.g. cat file | grep pattern still shows its real output; find src | sort chains aren't swallowed)
  • No test suite in this repo beyond the log files themselves - logs/ is gitignored, so this PR touches only format-stream.jq and overnight.sh

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com

Summary by CodeRabbit

  • New Features

    • Added stateful stream processing for clearer, structured event and tool-result output.
    • Added concise summaries for common file, search, test, lint, type-checking, shell, and Git operations.
    • Added handling for truncation, indentation, and tool-result correlation.
  • Bug Fixes

    • Removed ANSI escape sequences, carriage-return artifacts, and unnecessary diff noise.
    • Suppressed output from inspection-only commands when it provides no actionable information.
    • Preserved tool errors in the stderr log after stream completion, while removing empty logs.

c0d3ster and others added 4 commits August 6, 2026 14:27
- strip_ansi removes raw escape sequences from tool output before
  truncation, so colored subprocess output (e.g. vitest) no longer
  shows up as garbled control-byte text in the readable .log
- format-stream.jq now walks the stream statefully via foreach,
  correlating tool_result events back to their tool_use by id
- Read tool_result lines are dropped entirely: the paired
  '> Read(...)' line already shows file path and offset/limit, so
  the truncated file-content dump was pure redundant noise
- overnight.sh appends genuine tool/harness errors (is_error
  results - permission denials, bad exit codes, missing files) to
  the same errlog used for the claude process's own stderr, then
  deletes the file if nothing landed in it

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Glob/Grep results collapse to a one-line count summary instead of
  dumping every matched path/line
- Bash results get tool-aware summarization: vitest's Test
  Files/Tests lines plus each FAILED test, tsc's error lines plus
  the closing Found-N-errors line, eslint's problems re-attached to
  their file, and a last-line collapse for bracketed-status tool
  output (e.g. codegen's [STARTED]/[SUCCESS] chatter)
- pure file-inspection Bash chains (cat/ls/echo/head/tail joined by
  &&/;/||, e.g. "cat a && echo --- && cat b") are suppressed
  entirely, same rationale as the existing Read suppression - the
  request line already shows what was inspected
- strip_cr removes stray \r bytes so Windows-line-ended file dumps
  don't render as phantom blank lines
- indent_continuations aligns multi-line result bodies under the
  "    < " prefix instead of falling back to column 0

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- add find to the pure-inspect verb group so fallback chains like
  "cat a.ts || cat a.yml || find . -iname ..." get suppressed
- add a second inspect group for tasklist/ps (with an allowed
  "| grep" suffix) so process-listing checks don't dump PIDs/memory
- loosen the bracket-tag collapse: real tool output often has
  preamble before the [STARTED]/[SUCCESS] lines, so require only 2+
  tagged lines plus a completion-looking last line instead of nearly
  every line being tagged
- Bash-invoked "grep ... " calls (optionally behind "cd ... &&" and
  a trailing "| head/tail") now get the same one-line match-count
  summary as the dedicated Grep tool instead of a raw line dump

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- git status --short/-s condenses to a per-status-code count (e.g.
  "15 modified, 2 untracked") instead of truncating to the last 5
  files, which was silently dropping real changes on anything larger
- git commit output drops the lefthook/commitlint box-drawing noise
  and per-file create/delete-mode listing, keeping just the
  "[branch hash] subject" line and the diffstat
- the request line for a "git commit -m ..." call now shows just
  the commit title instead of raw-truncating the JSON-embedded
  multi-line message mid-body
- git's core.autocrlf "LF will be replaced by CRLF" warnings are
  stripped everywhere - never actionable
- git diff output is dropped entirely (redundant with the PR itself)
- Bash-run dev server startup collapses to just the "Ready in Xs"
  line when present; startup failures still fall through to the
  existing tail-5 fallback

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The formatter now processes NDJSON streams with stateful tool-use correlation, cleaned tool output, tool-specific summaries, inspection suppression, and truncation. overnight.sh records cleaned tool errors in the stderr log after stream completion.

Changes

Stream formatting and error capture

Layer / File(s) Summary
Tool output normalization and summaries
format-stream.jq
Adds terminal cleanup, continuation indentation, tool-result normalization, tool-specific summaries, and Bash inspection filtering.
Stateful event formatting
format-stream.jq
Tracks assistant tool-use IDs with foreach and formats correlated results with filtering, summaries, truncation, and cleanup.
Post-stream error capture
overnight.sh
Extracts tool errors from raw_log, strips ANSI sequences, appends messages to errlog, and removes empty stderr logs.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Claude as Claude stream
  participant Formatter as format-stream.jq
  participant Results as Tool results
  participant Overnight as overnight.sh
  Claude->>Formatter: Emit NDJSON events
  Formatter->>Formatter: Store tool-use IDs
  Results-->>Formatter: Provide scalar or array content
  Formatter->>Formatter: Clean and summarize correlated output
  Formatter-->>Claude: Emit formatted events
  Claude->>Overnight: Complete stream and raw_log
  Overnight->>Overnight: Extract, clean, and append tool errors
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes to declutter and clarify readable session logs.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/readable-log-cleanup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@format-stream.jq`:
- Around line 199-214: Update the tool-result branching in format-stream.jq to
handle .is_error == true before the Read and pure-inspection Bash suppression
branches. Write failed correlated inspection results through to the live
readable output, while preserving suppression for successful Read and
pure-inspection Bash results and existing formatting for Glob and Grep.
- Around line 11-12: Update strip_ansi in format-stream.jq (format-stream.jq
lines 11-12) and the matching error handler in overnight.sh (overnight.sh line
130) to use the complete CSI escape-sequence pattern, including optional
private-mode markers such as ?. Ensure both log paths remove sequences like
ESC[?25l.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 46e4221b-4bdf-4604-bfff-19ab3d0ed37c

📥 Commits

Reviewing files that changed from the base of the PR and between c5040c6 and 7a0a6d1.

📒 Files selected for processing (2)
  • format-stream.jq
  • overnight.sh

Comment thread format-stream.jq
Comment on lines +11 to +12
def strip_ansi:
gsub("\\[[0-9;]*[a-zA-Z]"; "");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

sample=$'\033[?25lhidden\033[0m'

printf '%s' "$sample" |
  jq -Rr 'gsub("\u001b\\[[0-9;]*[a-zA-Z]"; "")' |
  od -An -tx1

printf '%s' "$sample" |
  jq -Rr 'gsub("\u001b\\[[0-?]*[ -/]*[`@-`~]"; "")' |
  od -An -tx1

Repository: c0d3ster/nightlight

Length of output: 197


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Files:\n'
git ls-files | rg '(^|/)(format-stream\.jq|overnight\.sh)$' || true

printf '\nRelevant snippets:\n'
if [ -f format-stream.jq ]; then
  nl -ba format-stream.jq | sed -n '1,25p'
fi
if [ -f overnight.sh ]; then
  nl -ba overnight.sh | sed -n '120,140p'
fi

printf '\nPattern occurrences:\n'
rg -n 'gsub\("\u001b|\[0-9;\]\*|\[0-?]\*\|private|CSI|strip_ansi' format-stream.jq overnight.sh || true

printf '\nBehavioral probe with Python (no repo code/exec):\n'
python3 - <<'PY'
import re
samples = [
    "\033[?25lhidden\033[0m",
    "\033[?1049h\033[2J\033[H",
    "\033[38;2;255;128;0mcolored",
]
patterns = {
    "current": re.compile(r"\x1b\[[0-9;]*[a-zA-Z]"),
    "complete": re.compile(r"\x1b\[[0-?]*[ -/]*[`@-`~]"),
}
for sample in samples:
    print(f"INPUT={sample!r}")
    for name, re_pat in patterns.items():
        print(f"  {name}={re_pat.sub('', sample)!r}")
PY

Repository: c0d3ster/nightlight

Length of output: 254


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Relevant snippets:\n'
if [ -f format-stream.jq ]; then
  line=1
  while IFS= read -r content || [ -n "$content" ]; do
    printf '%d:%s\n' "$line" "$content"
    [ "$line" -ge 25 ] && break
    line=$((line + 1))
  done < format-stream.jq
fi
if [ -f overnight.sh ]; then
  line=1
  while IFS= read -r content || [ -n "$content" ]; do
    printf '%d:%s\n' "$line" "$content"
    [ "$line" -ge 140 ] && break
    line=$((line + 1))
  done < overnight.sh
fi

printf '\nPattern occurrences:\n'
rg -n 'gsub\("\u001b|\[0-9;\]\*|\[0-?]\*\|private|CSI|strip_ansi' format-stream.jq overnight.sh nightly.sh .github 2>/dev/null || true

printf '\nBehavioral probe with Python:\n'
python3 - <<'PY'
import re

samples = [
    "\033[?25lhidden\033[0m",
    "\033[?1049h\033[2J\033[H",
    "\033[38;2;255;128;0mcolored",
]

patterns = {
    "current": re.compile(r"\x1b\[[0-9;]*[a-zA-Z]"),
    "complete": re.compile(r"\x1b\[[0-?]*[ -/]*[`@-`~]"),
}

for sample in samples:
    print(f"INPUT={sample!r}")
    for name, regex in patterns.items():
        print(f"  {name}={regex.sub('', sample)!r}")
PY

Repository: c0d3ster/nightlight

Length of output: 8535


Remove private CSI escape sequences in both log paths.

Use the complete CSI regex in format-stream.jq and the matching error handler in overnight.sh so private sequences such as ESC[?25l do not remain in the logs.

📍 Affects 2 files
  • format-stream.jq#L11-L12 (this comment)
  • overnight.sh#L130-L130
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@format-stream.jq` around lines 11 - 12, Update strip_ansi in format-stream.jq
(format-stream.jq lines 11-12) and the matching error handler in overnight.sh
(overnight.sh line 130) to use the complete CSI escape-sequence pattern,
including optional private-mode markers such as ?. Ensure both log paths remove
sequences like ESC[?25l.

Comment thread format-stream.jq
Comment on lines +199 to +214
if $tool_name == "Read" then
empty
elif $tool_name == "Glob" then
($text | non_empty_lines | length) as $n |
" < found " + ($n | tostring) +
(if $n == 1 then " file matching \"" else " files matching \"" end) +
($tool.input.pattern // "?") + "\""
elif $tool_name == "Grep" then
($text | non_empty_lines | length) as $n |
($tool.input.output_mode == "files_with_matches") as $is_files |
" < " + ($n | tostring) +
(if $is_files then (if $n == 1 then " file" else " files" end)
else (if $n == 1 then " match" else " matches" end) end) +
" for \"" + ($tool.input.pattern // "?") + "\""
elif $tool_name == "Bash" and is_pure_inspect($tool.input.command // "") then
empty

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 4 'is_error|tool_name == "Read"|is_pure_inspect' format-stream.jq overnight.sh

Repository: c0d3ster/nightlight

Length of output: 2951


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- format-stream.jq relevant sections ---'
sed -n '1,80p;110,145p;175,235p' format-stream.jq

echo
echo '--- overnight.sh relevant sections ---'
sed -n '100,135p' overnight.sh

Repository: c0d3ster/nightlight

Length of output: 9127


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '{
"type":"user","message":{"content":[{"type":"tool_result","tool_use_id":"1","is_error":true,"content":"Read failed: missing file at /tmp/missing.txt"}]}}
' | jq -r -f format-stream.jq

printf '%s\n' '{
"type":"user","message":{"content":[{"type":"tool_result","tool_use_id":"2","is_error":true,"content":"bash -i exited 1"}], "previous_event_id":"old"}}, {
"type":"assistant","message":{"content":[{"type":"tool_use","id":"1","name":"Read","input":{"file":"/tmp/missing.txt"}}]}
' | jq -n  --slurp -r -f format-stream.jq

Repository: c0d3ster/nightlight

Length of output: 283


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '{
"type":"assistant","message":{"content":[{"type":"tool_use","id":"1","name":"Read","input":{"file":"/tmp/missing.txt"}}]}
},{
"type":"user","message":{"content":[{"type":"tool_result","tool_use_id":"1","is_error":true,"content":"Read failed: missing file at /tmp/missing.txt"}]}}
' | jq -r -f format-stream.jq

printf '%s\n' '{
"type":"assistant","message":{"content":[{"type":"tool_use","id":"2","name":"Bash","input":{"command":"cat /tmp/missing.txt"}}]}
},{
"type":"user","message":{"content":[{"type":"tool_result","tool_use_id":"2","is_error":true,"content":"cat: /tmp/missing.txt: No such file or directory"}]}}
' | jq -r -f format-stream.jq

printf '%s\n' '{
"type":"user","message":{"content":[{"type":"tool_result","tool_use_id":"3","is_error":true,"content":"permission denied"}]}}
' | jq -r -f format-stream.jq

Repository: c0d3ster/nightlight

Length of output: 400


Expose failed inspection tool errors before suppression.

When a correlated tool_result has .is_error == true, the Read and pure-inspection Bash branches currently emit no live output while overnight.sh only appends the error after stream processing finishes. Let failed inspection results write through, e.g. in a shared first check, so the live readable log does not hide actionable tool failures.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@format-stream.jq` around lines 199 - 214, Update the tool-result branching in
format-stream.jq to handle .is_error == true before the Read and pure-inspection
Bash suppression branches. Write failed correlated inspection results through to
the live readable output, while preserving suppression for successful Read and
pure-inspection Bash results and existing formatting for Glob and Grep.

@c0d3ster
c0d3ster merged commit ac15e47 into main Aug 6, 2026
1 check passed
@c0d3ster
c0d3ster deleted the fix/readable-log-cleanup branch August 6, 2026 20:41
c0d3ster added a commit that referenced this pull request Aug 6, 2026
- #11 [stack: solo] Make DB schema/migration generation NEEDS HUMAN
- Amend #2's NEEDS HUMAN trial to require a cache-read cost comparison
  against the 2026-08-06 baseline before adopting split-per-task as default
- nextTaskNumber -> 12 (only #11 was formally assigned here; the
  out-of-band format-stream.jq log fix, PR #21, was never written into
  TASKS.md under a number, so it never consumed one)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
c0d3ster added a commit that referenced this pull request Aug 6, 2026
- #11 [stack: solo] Make DB schema/migration generation NEEDS HUMAN
- Amend #2's NEEDS HUMAN trial to require a cache-read cost comparison
  against the 2026-08-06 baseline before adopting split-per-task as default
- nextTaskNumber -> 12 (only #11 was formally assigned here; the
  out-of-band format-stream.jq log fix, PR #21, was never written into
  TASKS.md under a number, so it never consumed one)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant