Skip to content

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

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

feat(live): show tool call details in streaming output#253
visigoth wants to merge 1 commit into
frankbria: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

  • New Features

    • Optional runtime toggle/flag to show or hide truncated tool arguments inline during live streams.
  • Improvements

    • Shorter inline indicator for tool activity to reduce visual noise.
    • Per-turn consolidated summaries of tool use emitted after each assistant turn for quick context.
    • Reduced extra spacing in task-started/status messages.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Updated live streaming in ralph_loop.sh: jq filter now emits shorter inline tool-start markers, adds an assistant branch that summarizes tool-use lines from message.content[], optionally includes truncated tool arguments via a new --show-tool-args flag and LIVE_SHOW_TOOL_ARGS plumbing, and adjusts task_started newline formatting. (50 words)

Changes

Cohort / File(s) Summary
Live streaming jq filter & CLI plumbing
ralph_loop.sh
Reworked the live-stream jq pipeline to replace verbose tool-use banners with short inline markers (⚙ <tool>...), added an elif .type == "assistant" branch that scans message.content[] for tool_use blocks and emits consolidated ⚡ [<Tool>] ... lines, added --argjson show_args "${LIVE_SHOW_TOOL_ARGS:-false}" to control inclusion of truncated, type-specific tool arguments (Bash command; Read/Write/Edit file_path; Glob/Grep pattern; Agent/Task description), introduced _env_LIVE_SHOW_TOOL_ARGS / .ralphrc loading precedence and new CLI flag --show-tool-args, and removed an extra leading newline for task_started formatting.

Sequence Diagram(s)

sequenceDiagram
  participant User as "User (CLI)"
  participant Shell as "ralph_loop.sh"
  participant Claude as "Claude streaming API"
  participant JQ as "jq filter"
  participant Stdout as "Terminal stdout"

  User->>Shell: invoke with/without --show-tool-args
  Shell->>Claude: start streaming request
  Claude-->>Shell: stream events (content_block_start, assistant, task_started, ...)
  Shell->>JQ: pipe streaming JSON + --argjson show_args
  JQ-->>Shell: formatted lines (⚙ tool..., ⚡ [Tool] ..., task_started ...)
  Shell->>Stdout: emit live lines to terminal
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐇✨ I nibble banners down to seed-sized marks,
Turning long tool roars into tidy sparks.
Show the args when carrots gleam,
Otherwise keep streams sleek and lean.
Hop, trim, and stream — a rabbit's little scheme.

🚥 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 and specifically describes the main change: enhancing live streaming output to display tool call details alongside tool names.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
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.

@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
@frankbria
Copy link
Copy Markdown
Owner

Looks like you still need to rebase.

@visigoth visigoth force-pushed the feat/live-streaming-improvements branch from 57fe9c7 to 391c076 Compare April 25, 2026 03:45
@visigoth
Copy link
Copy Markdown
Contributor Author

Looks like you still need to rebase.

sorry for taking a while to do so

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 1606-1607: The jq invocation using --argjson show_args
"${LIVE_SHOW_TOOL_ARGS:-false}" can abort on non-JSON values (e.g., "yes", "on",
"1 ", "True") and its stderr is currently thrown away; normalize
LIVE_SHOW_TOOL_ARGS into a strict JSON literal before invoking portable_timeout
and pipe jq stderr to $stderr_file (same as Claude) so failures are visible.
Implement normalization by trimming whitespace and lowercasing (use
POSIX-compatible tools like printf/tr and case mapping) to convert common truthy
values ("yes","on","true","1") to the JSON literal true and everything else to
false, then pass that normalized value to jq's --argjson show_args; also
redirect jq stderr (the pipeline segment with jq) to $stderr_file instead of
/dev/null.
🪄 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: 713fea27-fcd0-40bd-8832-2c25588ce2e4

📥 Commits

Reviewing files that changed from the base of the PR and between 57fe9c7 and 391c076.

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

Comment thread ralph_loop.sh Outdated
@visigoth visigoth force-pushed the feat/live-streaming-improvements branch 2 times, most recently from 43f0189 to 3ca05d0 Compare April 25, 2026 03:57
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

♻️ Duplicate comments (1)
ralph_loop.sh (1)

1607-1609: ⚠️ Potential issue | 🟡 Minor

--argjson still receives raw LIVE_SHOW_TOOL_ARGS; combined with 2>/dev/null it can silently blank the live pane.

This was raised on the previous commit and is still unaddressed. --argjson show_args "${LIVE_SHOW_TOOL_ARGS:-false}" requires a strict JSON literal, so any non-canonical value reaching this point — yes, on, True, 1, a trailing space, or even an accidental quoted "true" from .ralphrc — makes jq abort with argjson takes JSON as argument. Because jq's stderr is sent to /dev/null, the live pane goes empty with no diagnostic while tee "$output_file" keeps writing the raw stream, so the failure mode looks like "live mode broke" rather than "config typo".

Two small fixes are worth applying together: normalize the value to a strict JSON boolean and route jq's stderr to $stderr_file so a future misconfiguration is at least visible.

🛡️ Suggested normalization + stderr capture
+        # Normalize LIVE_SHOW_TOOL_ARGS to a strict JSON boolean for --argjson.
+        # jq aborts on non-JSON values (yes/on/1/True/quoted "true"); anything
+        # other than a recognized truthy token is treated as false.
+        local show_args_json="false"
+        case "$(printf '%s' "${LIVE_SHOW_TOOL_ARGS:-false}" | tr -d '[:space:]"' | tr '[:upper:]' '[:lower:]')" in
+            true|1|yes|on) show_args_json="true" ;;
+        esac
+
         portable_timeout ${timeout_seconds}s "${LIVE_CMD_ARGS[@]}" \
-            < /dev/null 2>"$stderr_file" | tee "$output_file" | jq --unbuffered -j --argjson show_args "${LIVE_SHOW_TOOL_ARGS:-false}" "$jq_filter" 2>/dev/null | tee "$LIVE_LOG_FILE"
+            < /dev/null 2>"$stderr_file" \
+            | tee "$output_file" \
+            | jq --unbuffered -j --argjson show_args "$show_args_json" "$jq_filter" 2>>"$stderr_file" \
+            | tee "$LIVE_LOG_FILE"

As per coding guidelines, "Use POSIX-compatible bash features (e.g., tr for case conversion instead of ${,,}) to support bash 3.x environments".

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

In `@ralph_loop.sh` around lines 1607 - 1609, The jq invocation using --argjson
show_args "${LIVE_SHOW_TOOL_ARGS:-false}" can fail on non-strict JSON values and
its stderr is discarded; update the pipeline around the portable_timeout
invocation so LIVE_SHOW_TOOL_ARGS is normalized to a strict JSON boolean (e.g.,
map common truthy strings like yes/on/true/1 to true and everything else to
false using POSIX-safe tools such as tr and a case test) and pass that
normalized literal to jq's --argjson, and also redirect jq's stderr to
"$stderr_file" instead of /dev/null so failures from jq (invoked in the command
that writes to "$output_file" and "$LIVE_LOG_FILE") are captured in stderr_file
for diagnostics.
🤖 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 2527-2530: The CLI flag handler for --show-tool-args sets
LIVE_SHOW_TOOL_ARGS but doesn't preserve/re-apply it after load_ralphrc; mimic
the existing --backup pattern by (1) when parsing the flag set a sentinel like
_cli_LIVE_SHOW_TOOL_ARGS=true in the same block that currently sets
LIVE_SHOW_TOOL_ARGS, (2) after load_ralphrc in main re-apply/override
LIVE_SHOW_TOOL_ARGS if _cli_LIVE_SHOW_TOOL_ARGS is set (same place and style as
the _cli_ENABLE_BACKUP re-application), and (3) ensure any existing
_env_LIVE_SHOW_TOOL_ARGS restore logic remains unchanged so exported env
variables still behave the same.

---

Duplicate comments:
In `@ralph_loop.sh`:
- Around line 1607-1609: The jq invocation using --argjson show_args
"${LIVE_SHOW_TOOL_ARGS:-false}" can fail on non-strict JSON values and its
stderr is discarded; update the pipeline around the portable_timeout invocation
so LIVE_SHOW_TOOL_ARGS is normalized to a strict JSON boolean (e.g., map common
truthy strings like yes/on/true/1 to true and everything else to false using
POSIX-safe tools such as tr and a case test) and pass that normalized literal to
jq's --argjson, and also redirect jq's stderr to "$stderr_file" instead of
/dev/null so failures from jq (invoked in the command that writes to
"$output_file" and "$LIVE_LOG_FILE") are captured in stderr_file for
diagnostics.
🪄 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: 8d28540b-4e4b-4303-b432-a830f6f5060e

📥 Commits

Reviewing files that changed from the base of the PR and between 391c076 and 43f0189.

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

Comment thread ralph_loop.sh
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 3ca05d0 to b40690b Compare April 25, 2026 04:05
@visigoth visigoth requested a review from frankbria April 27, 2026 03:40
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