Skip to content

feat(live): show tool call details in streaming output#253

Open
visigoth wants to merge 1 commit intofrankbria:mainfrom
visigoth:feat/live-streaming-improvements
Open

feat(live): show tool call details in streaming output#253
visigoth wants to merge 1 commit intofrankbria:mainfrom
visigoth:feat/live-streaming-improvements

Conversation

@visigoth
Copy link
Copy Markdown
Contributor

@visigoth visigoth commented Apr 11, 2026

Summary

Improves Ralph's --live / --monitor streaming output so the operator can actually see what Claude is doing during a loop iteration, not just that a tool was invoked.

Before this change, the streaming jq filter only had access to stream_event content_block_start events, which carry the tool name but no arguments (the input is delivered later as deltas). The result on screen was a blank ⚡ [Bash] marker with no command, file path, or pattern — useful for confirming activity but not for following along.

This PR keeps the immediate "tool starting" indicator and adds a richer second pass driven by full assistant messages, which arrive at the end of each turn with complete tool inputs.

What changes in the live feed

  • Immediate (stream_event content_block_start): ⚙ Bash... — confirms a tool just started, with no args yet.
  • After turn completes (assistant message): ⚡ [Bash] git status --short — the full first-line summary, truncated to 120 chars.
  • Per-tool extraction:
    • Bash → first line of command, capped at 120 chars
    • Read / Write / Editfile_path
    • Glob / Greppattern
    • Agentdescription
    • Other tools → name only
  • Tightened up some leading-newline noise around 🚀 Agent: and markers for a less spread-out feed.

Files

  • ralph_loop.sh — single-file change to the jq filter inside the live streaming pipeline. +38 / -3.

Why it's safe

  • Purely a presentation change to the live output filter; no control flow, no exit detection, no session handling touched.
  • Falls through to empty for unknown tool types, so future tools won't break the filter.
  • The original stream_event branch is preserved, so the immediate "tool started" indicator still fires even before the assistant message arrives.

Test plan

  • ralph --monitor against a project that triggers a mix of Bash, Read, Edit, and Grep calls — confirm each call shows a meaningful summary line
  • ralph --live (without tmux) shows the same enriched feed
  • A Bash command longer than 120 chars is truncated, not wrapped
  • A multi-line Bash heredoc shows only the first line in the live feed
  • Sub-agent (Agent) invocations show the description string
  • npm test still passes

Summary by CodeRabbit

  • Improvements
    • More concise in-stream indicator for tool activity, reducing visual noise during live streaming.
    • Per-turn, per-tool summary lines now appear after each assistant turn, showing truncated command/file/pattern/description details for quick context.
    • New configurable option to include or hide truncated tool argument/details inline.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 11, 2026

Walkthrough

Updated the LIVE-mode jq filter in ralph_loop.sh to condense tool activity markers, add an assistant branch that emits per-tool summary lines by extracting and normalizing tool arguments, and wire a new LIVE_SHOW_TOOL_ARGS boolean into the jq filter; other streaming and system message handling remains unchanged.

Changes

Cohort / File(s) Summary
Live Streaming Output Filter
ralph_loop.sh
Expanded the Claude live-stream jq filter: replaced the verbose tool-start marker with \n⚙ <tool>..., added an elif .type == "assistant" branch that scans message.content[] for tool_use blocks and emits per-tool summary lines (⚡ [<Tool>] <details>\n), introduced --argjson show_args "${LIVE_SHOW_TOOL_ARGS:-false}" and a new LIVE_SHOW_TOOL_ARGS env/global variable, and implemented type-specific argument extraction/truncation (Bash command; Read/Write/Edit file path; Glob/Grep pattern; Agent/Task description). Existing text_delta, content_block_stop, and system task_started/task_progress branches are unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐇✨ I nibble tokens, tidy the trail,
Turning long markers into a compact tale.
Tools wink brief, arguments trimmed fine,
Live-stream hops neat — a carrot-shaped line.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly describes the main change: adding tool call details to the live streaming output display in Ralph.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feat/live-streaming-improvements

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

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 the current code and only fix it if needed.

Inline comments:
In `@ralph_loop.sh`:
- Around line 1563-1581: The tool-summary jq expression only strips newlines and
truncates for the "Bash" branch; update the other branches ("Read", "Write",
"Edit", "Glob", "Grep", "Agent") so their values are normalized the same way by
replacing raw emissions like (.input.file_path // ""), (.input.pattern // ""),
and (.input.description // "") with the same pipeline used for Bash (fallback to
"", split on "\n", take first line, truncate to 120 chars) in the jq string
construction around the tool summary generation.
- Around line 1576-1577: The current conditional only handles subagents named
"Agent" and drops descriptions from older versions that use "Task"; update the
condition that checks .name (the clause currently written as .name == "Agent")
to accept both "Agent" and "Task" (e.g., use a logical OR or an IN check so the
branch triggers for either name) and keep the existing extraction of
(.input.description // "") so the summary includes the description for both tool
names.
🪄 Autofix (Beta)

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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4f7e8518-6b1c-4126-a984-38ccfff6e24b

📥 Commits

Reviewing files that changed from the base of the PR and between 2265569 and 7767280.

📒 Files selected for processing (1)
  • ralph_loop.sh

Comment thread ralph_loop.sh Outdated
@visigoth visigoth force-pushed the feat/live-streaming-improvements branch from 7767280 to 90b904d Compare April 12, 2026 03:28
@visigoth
Copy link
Copy Markdown
Contributor Author

Both CodeRabbit findings addressed in the force-pushed commit:

  1. ralph_loop.sh:1577 — subagent tool name alias (major). The condition is now .name == "Agent" or .name == "Task", so the description is preserved for both the current tool name and the legacy name used by Claude Code versions prior to v2.1.63 (Ralph's minimum supported version is v2.0.76).

  2. ralph_loop.sh:1581 — one-line/120-char rule applied uniformly (minor). Refactored the filter so each tool type only extracts its raw summary field, and then a single normalization pipeline (| split("\n") | .[0] | .[0:120]) runs on the result. Bash command, Read/Write/Edit file_path, Glob/Grep pattern, and Agent/Task description are all now trimmed to the first line and truncated to 120 chars. A multiline file_path or long grep pattern can no longer blow up the live pane.

Smoke-tested the filter directly with jq -f against fixtures covering every tool type including multiline inputs, over-length paths, the legacy Task alias, and unknown tools. All produce the expected one-line output.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ralph_loop.sh`:
- Around line 1570-1584: The logging code that builds the tool-line (the
expression that checks .name == "Bash"/"Agent"/etc. and pulls
.input.command/.input.description) is emitting raw tool arguments into logs;
change it to redact or summarize sensitive content by default: replace direct
uses of (.input.command/.input.description/.input.file_path/.input.pattern) with
a sanitizer function (e.g., redact_sensitive()) that strips/obfuscates tokens,
secrets, long hex strings, URLs, emails, and common key=secret patterns and
returns a short safe summary (or "[REDACTED]" when unknown), and add an explicit
opt-in flag (e.g., ENABLE_VERBOSE_TOOL_ARGS) so full raw arguments are only
logged when explicitly enabled; update the branches for "Bash" and "Agent" to
call that sanitizer (or produce one-line summaries like "<command redacted>" /
first non-sensitive word) instead of writing raw input and keep the 120-char cut
as a secondary guard.
🪄 Autofix (Beta)

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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a8fd19e0-d0bc-46ad-9f32-98fe681fb562

📥 Commits

Reviewing files that changed from the base of the PR and between 7767280 and 90b904d.

📒 Files selected for processing (1)
  • ralph_loop.sh

Comment thread ralph_loop.sh
Comment on lines +1570 to +1584
"\n⚡ [" + .name + "] " + (
(
if .name == "Bash" then
(.input.command // "")
elif .name == "Read" or .name == "Write" or .name == "Edit" then
(.input.file_path // "")
elif .name == "Glob" or .name == "Grep" then
(.input.pattern // "")
elif .name == "Agent" or .name == "Task" then
(.input.description // "")
else
""
end
) | split("\n") | .[0] | .[0:120]
) + "\n"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don't log raw tool arguments by default.

This branch now emits first-line Bash commands and Agent descriptions straight into the live pane/log, so any token, secret, URL, username, or prompt text carried in tool input gets persisted to disk. The 120-char cutoff does not materially reduce that exposure. Please redact common secret-bearing patterns or make argument-level summaries explicitly opt-in instead of always logging them.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ralph_loop.sh` around lines 1570 - 1584, The logging code that builds the
tool-line (the expression that checks .name == "Bash"/"Agent"/etc. and pulls
.input.command/.input.description) is emitting raw tool arguments into logs;
change it to redact or summarize sensitive content by default: replace direct
uses of (.input.command/.input.description/.input.file_path/.input.pattern) with
a sanitizer function (e.g., redact_sensitive()) that strips/obfuscates tokens,
secrets, long hex strings, URLs, emails, and common key=secret patterns and
returns a short safe summary (or "[REDACTED]" when unknown), and add an explicit
opt-in flag (e.g., ENABLE_VERBOSE_TOOL_ARGS) so full raw arguments are only
logged when explicitly enabled; update the branches for "Bash" and "Agent" to
call that sanitizer (or produce one-line summaries like "<command redacted>" /
first non-sensitive word) instead of writing raw input and keep the 120-char cut
as a secondary guard.

Copy link
Copy Markdown
Owner

@frankbria frankbria left a comment

Choose a reason for hiding this comment

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

The enriched live feed is a nice improvement — seeing ⚡ [Bash] git status --short instead of a blank marker is much more useful. A few things to address before merging:

Blocking

Sensitive data in logs (security)
The jq filter emits raw tool arguments — Bash commands, file paths, grep patterns — directly into the live log. In practice these can contain secrets: aws configure set aws_secret_access_key ..., tokens passed as env vars, or credentials in file paths. Recommend either:

  • Adding a sanitizer that redacts common secret patterns (e.g., long hex/base64 strings, key=value where key contains "secret"/"token"/"password"), or
  • Gating full argument output behind an opt-in flag like ENABLE_VERBOSE_TOOL_ARGS=true and emitting a safe summary by default (e.g. the command verb only for Bash)

This is particularly important since --live and --monitor output is often captured to a log file.

Non-blocking but please fix

Inconsistent normalization across tool branches
Only the Bash branch strips newlines and truncates to 120 chars. Read, Write, Edit, Glob, Grep, and Agent emit raw values that can contain newlines or be arbitrarily long. Apply the same normalization pipeline to all branches.

Missing Task tool name
The Agent branch only matches .name == "Agent". Older Claude CLI versions use "Task" as the tool name. Change the condition to match both:

elif .name == "Agent" or .name == "Task" then

Also: please rebase

PR #256 (a 1-line crash fix in ralph_loop.sh) is being merged first. Please rebase this branch onto main after that lands, since both touch ralph_loop.sh.

Once the security concern is addressed and the other items fixed, happy to re-review.

The jq filter only showed tool names (⚡ [Bash]) with no arguments,
making live mode appear empty when Claude does mostly tool calls.

Now shows two levels of feedback:
- ⚙ Bash... (immediate, from stream_event content_block_start)
- ⚡ [Bash] actual command here (full args, from assistant message)

Also removes stdbuf dependency check since stdbuf was removed in prior commit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@visigoth visigoth force-pushed the feat/live-streaming-improvements branch from 90b904d to 57fe9c7 Compare April 14, 2026 19:07
@visigoth
Copy link
Copy Markdown
Contributor Author

Tool argument details are now opt-in via LIVE_SHOW_TOOL_ARGS (defaults to false).

Default behavior (false): The live pane shows tool names only — ⚡ [Bash], ⚡ [Read], etc. — with no commands, file paths, or patterns logged. This avoids leaking tokens, secrets, or prompt text into the live log.

Opt-in (LIVE_SHOW_TOOL_ARGS=true in .ralphrc or env): Restores the detailed summaries — ⚡ [Bash] git status --short, ⚡ [Read] src/main.rs, etc. — still normalized to first line / 120 chars.

Implementation: the flag is passed into the jq filter as --argjson show_args true|false, so the gating is evaluated per-event inside the streaming pipeline with zero overhead when disabled.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ralph_loop.sh`:
- Line 77: The LIVE_SHOW_TOOL_ARGS variable is undocumented, defaults to false,
and is bypassing the _env_* capture/restore flow; update the script so this
feature is discoverable and precedence-safe: add LIVE_SHOW_TOOL_ARGS handling
into load_ralphrc() (respecting env > .ralphrc precedence and ensuring it
participates in the _env_* capture/restore flow), expose it in show_help()
and/or add an explicit --show-tool-args CLI flag that sets LIVE_SHOW_TOOL_ARGS,
and update any places that read LIVE_SHOW_TOOL_ARGS (e.g., where the ⚡ [Tool]
output is emitted) to follow the new precedence and documented behavior.
🪄 Autofix (Beta)

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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b8738521-6109-44b2-a006-389e0c084fe6

📥 Commits

Reviewing files that changed from the base of the PR and between 90b904d and 57fe9c7.

📒 Files selected for processing (1)
  • ralph_loop.sh

Comment thread ralph_loop.sh
DRY_RUN="${DRY_RUN:-false}" # Simulate loop without making actual Claude API calls
ENABLE_NOTIFICATIONS="${ENABLE_NOTIFICATIONS:-false}" # Enable desktop notifications; set true or use --notify flag
ENABLE_BACKUP="${ENABLE_BACKUP:-false}" # Enable automatic git backups before each loop; set true or use --backup flag
LIVE_SHOW_TOOL_ARGS="${LIVE_SHOW_TOOL_ARGS:-false}" # Show tool arguments in live streaming output (file paths, commands, patterns)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

LIVE_SHOW_TOOL_ARGS is effectively hidden right now.

This defaults to false, has no CLI/help path, and skips the _env_* capture/restore flow. In practice, --live / --monitor users still just get a second ⚡ [Tool] marker unless they know to set an undocumented knob, and exported values can be overridden by .ralphrc even though the rest of the script treats environment as highest priority.

♻️ Minimal direction
+_env_LIVE_SHOW_TOOL_ARGS="${LIVE_SHOW_TOOL_ARGS:-}"
 ...
 LIVE_SHOW_TOOL_ARGS="${LIVE_SHOW_TOOL_ARGS:-false}"

Then mirror that in load_ralphrc() and expose the setting in show_help() or via an explicit --show-tool-args flag so the feature is discoverable and precedence-safe.

As per coding guidelines, "Documentation MUST remain synchronized with codebase: inline script comments for all functions, README updates for features, template file updates for patterns, and CLAUDE.md updates for new commands and behaviors".

Also applies to: 1610-1610

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ralph_loop.sh` at line 77, The LIVE_SHOW_TOOL_ARGS variable is undocumented,
defaults to false, and is bypassing the _env_* capture/restore flow; update the
script so this feature is discoverable and precedence-safe: add
LIVE_SHOW_TOOL_ARGS handling into load_ralphrc() (respecting env > .ralphrc
precedence and ensuring it participates in the _env_* capture/restore flow),
expose it in show_help() and/or add an explicit --show-tool-args CLI flag that
sets LIVE_SHOW_TOOL_ARGS, and update any places that read LIVE_SHOW_TOOL_ARGS
(e.g., where the ⚡ [Tool] output is emitted) to follow the new precedence and
documented behavior.

@frankbria
Copy link
Copy Markdown
Owner

Looks like you still need to rebase.

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.

2 participants