Skip to content

Keep recaps visible at all detail levels; add --no-recaps (#179)#209

Merged
cboos merged 3 commits into
mainfrom
dev/recaps-always-visible
Jun 7, 2026
Merged

Keep recaps visible at all detail levels; add --no-recaps (#179)#209
cboos merged 3 commits into
mainfrom
dev/recaps-always-visible

Conversation

@cboos

@cboos cboos commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

Closes #179.

Background

Recaps (※ recap / away_summary messages) are a high-level summary of the
activity that just happened. They were classified detail_visibility = HIGH,
so they were dropped at --detail low and below (an oversight from #141) —
exactly the levels where a one-line "user said this, agent did that" summary is
most useful.

What this does

Keep recaps visible at every detail level, and add --no-recaps to
suppress them when you don't want them.

  • AwaySummaryMessage.detail_visibility: HIGHUSER_ONLY (the
    least-verbose threshold), so recaps survive fulluser-only.
  • New --no-recaps flag, threaded through the renderers and converter. It
    suppresses recaps at any level, including full (so --detail full --no-recaps works). Honored by the HTML, Markdown, and JSON renderers.

Resulting matrix:

user agent recaps flags
--detail minimal (and above)
--detail minimal --no-recaps
--detail user-only
--detail user-only --no-recaps

Tests

  • Recap visible at all five detail levels + --no-recaps suppresses at all five.
  • End-to-end matrix test for the four rows above.
  • Cross-format coverage: --no-recaps honored by html / markdown / json.
  • Updated the minimal real-projects assertion to allow (and pin to a recap) the
    now-surviving recap.

dev-docs/messages.md and application_model.md updated.

Deferred follow-up

The issue lists a --detail session → (nothing) row marked "(maybe?)". That
would be a new detail level below user-only that renders no messages — a
separate feature (new DetailLevel value + "render nothing" semantics),
deliberately not included here. Tracked as a follow-up.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a --no-recaps option to suppress recap/away-summary messages in exports.
  • Changes

    • Recap messages are shown at all detail levels by default.
    • The --no-recaps behavior is applied consistently across HTML, Markdown, and JSON outputs and reflected in variant filenames.
  • Tests

    • Expanded tests to cover recap visibility matrix and suppression across formats.
  • Documentation

    • Guides updated to describe recap visibility and the new flag.

cboos and others added 2 commits June 7, 2026 18:06
Recaps (away_summary) are themselves a high-level summary of activity, so
they should stay visible at every detail level rather than being dropped at
LOW and below (an oversight from #141). Change AwaySummaryMessage's
detail_visibility from HIGH to USER_ONLY so recaps survive full → user-only,
and add a --no-recaps flag to suppress them at any level (including FULL).

- models.py: AwaySummaryMessage.detail_visibility = USER_ONLY.
- renderer.py: Renderer.no_recaps attr; generate_template_messages +
  _ghost_template_by_detail gain no_recaps (recaps ghosted when set); run the
  ghost pass when no_recaps is set even at FULL; get_renderer wires it.
- converter.py / cli.py: thread no_recaps through (mirrors no_timestamps);
  new --no-recaps CLI flag.
- Resulting matrix: minimal → user+agent+recaps; minimal --no-recaps →
  user+agent; user-only → user+recaps; user-only --no-recaps → user only.

Tests: rewrite the away_summary detail-level tests (visible at every level +
--no-recaps suppresses everywhere), add an end-to-end matrix test, and allow
the recap "system" type in the minimal real-projects assertion. dev-docs
(messages.md, application_model.md) updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address review on #179:

- Finding #1: --no-recaps was a silent no-op for --format json. The JSON
  renderer honors --detail (it runs the ghost pass via
  generate_template_messages) but didn't forward no_recaps, so recaps stayed
  in the JSON tree. Thread no_recaps=self.no_recaps into the json/renderer.py
  generate() call, matching html/markdown.
- Add TestNoRecapsAllFormats exercising --no-recaps across html/md/json via
  the real get_renderer path (the existing matrix tests were HTML-only, which
  is why the JSON gap slipped).
- N1: tighten the minimal real-projects assertion — assert every surviving
  system-typed message is specifically a recap (AwaySummaryMessage), guarding
  against a future system subclass leaking in.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8d696e33-f3c8-4674-ae4a-395ed4f8574a

📥 Commits

Reviewing files that changed from the base of the PR and between c635783 and a0ef294.

📒 Files selected for processing (6)
  • claude_code_log/converter.py
  • claude_code_log/html/renderer.py
  • claude_code_log/json/renderer.py
  • claude_code_log/markdown/renderer.py
  • claude_code_log/utils.py
  • test/test_output_paths.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • claude_code_log/json/renderer.py

📝 Walkthrough

Walkthrough

Adds a --no-recaps CLI flag and threads it through get_renderer, converters, and all format renderers; makes AwaySummary (recap) messages visible at USER_ONLY by default and implements renderer-level ghosting to suppress recaps when --no-recaps is set. Tests and docs updated accordingly.

Changes

Recap Visibility and Suppression

Layer / File(s) Summary
Recap visibility change to USER_ONLY
claude_code_log/models.py
AwaySummaryMessage.detail_visibility changed so recaps are visible at all detail levels (including USER_ONLY).
Core renderer no_recaps logic
claude_code_log/renderer.py
Added no_recaps parameter to generate_template_messages and _ghost_template_by_detail, added no_recaps field to Renderer, updated get_renderer to accept and set no_recaps; ghosting now hides AwaySummaryMessage when no_recaps is true.
Renderer implementations forward no_recaps
claude_code_log/html/renderer.py, claude_code_log/json/renderer.py, claude_code_log/markdown/renderer.py
HTML/JSON/Markdown renderers now pass self.no_recaps into template-message generation and include no_recaps in variant-suffix/back-link computations.
Converter function signatures and threading
claude_code_log/converter.py, claude_code_log/utils.py
Added no_recaps: bool = False to convert_jsonl_to, generate_single_session_file, and process_projects_hierarchy; threaded flag into paginated and per-session generation and into get_renderer(..., no_recaps=...). variant_suffix gains no_recaps and adds a .no-recaps component when true.
CLI flag and wiring
claude_code_log/cli.py
Added Click option --no-recaps and threaded the parameter through main into single-session export, multi-project processing, and single-file/directory conversion calls.
Test refactor and documentation
test/test_away_summary.py, test/test_detail_levels.py, test/test_output_paths.py, dev-docs/application_model.md, dev-docs/messages.md
Refactored and extended tests to verify recap presence at all detail levels and suppression with --no-recaps across html/md/json; tightened MINIMAL constraints to allow only recap-style system messages; added variant-suffix tests and updated developer docs to reflect new semantics.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • daaain

"A rabbit hops through lines of code,
threading flags where recaps rode.
USER_ONLY now lets them peep,
until you tell them 'silence, keep' —
--no-recaps, and quiet grows the load." 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.89% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and specifically describes the main changes: making recaps visible at all detail levels and adding a --no-recaps flag to suppress them.
Linked Issues check ✅ Passed The PR fully implements all coding requirements from #179: recaps visible at all detail levels (AwaySummaryMessage.detail_visibility changed to USER_ONLY), --no-recaps flag threaded through converter/renderers, and cross-format support (HTML/Markdown/JSON) with comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the PR objectives and #179 requirements. Documentation updates explain the new behavior, and test updates validate the recap visibility matrix across detail levels and formats.

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

✨ 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 dev/recaps-always-visible

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.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
claude_code_log/converter.py (1)

1309-1310: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

--no-recaps is not part of variant/cache identity, so cached runs can ignore the flag.

Line 1571 (and the same suffix pattern at Lines 1309, 1985, 2232, 2398) builds variant keys without no_recaps. Since stale checks and fast-path skips are keyed by those suffixes, switching --no-recaps can still hit “up to date” and return recap-inclusive output.

Suggested fix direction
- suffix = _variant_suffix(detail, compact, format, no_timestamps)
+ suffix = _variant_suffix(detail, compact, format, no_timestamps)
+ if no_recaps:
+     suffix = f"{suffix}.no-recaps" if suffix else ".no-recaps"

Apply the same suffix decoration everywhere variant/suffix is computed for:

  • combined output path selection
  • page cache keys
  • per-session filenames
  • project index variant enumeration inputs

Also applies to: 1571-1571, 1985-1985, 2232-2232, 2398-2400

🤖 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 `@claude_code_log/converter.py` around lines 1309 - 1310, The suffix used to
build variant/cache keys (produced via calls to _variant_suffix and assigned to
the local variable suffix) currently omits the no_recaps flag, causing
cached/stale checks to ignore --no-recaps; update all places that compute
variant suffixes (every call/assignment of suffix/_variant_suffix at the shown
sites and the similar patterns used for combined output path selection, page
cache keys, per-session filenames, and project index variant enumeration inputs)
to include the no_recaps state (e.g., incorporate the boolean or its name into
the variant key generation), ensuring the variant identity reflects the
--no-recaps option so cached fast-paths and stale checks respect it.
🤖 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.

Outside diff comments:
In `@claude_code_log/converter.py`:
- Around line 1309-1310: The suffix used to build variant/cache keys (produced
via calls to _variant_suffix and assigned to the local variable suffix)
currently omits the no_recaps flag, causing cached/stale checks to ignore
--no-recaps; update all places that compute variant suffixes (every
call/assignment of suffix/_variant_suffix at the shown sites and the similar
patterns used for combined output path selection, page cache keys, per-session
filenames, and project index variant enumeration inputs) to include the
no_recaps state (e.g., incorporate the boolean or its name into the variant key
generation), ensuring the variant identity reflects the --no-recaps option so
cached fast-paths and stale checks respect it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7776841e-758a-438d-9e04-e209b8de1ba2

📥 Commits

Reviewing files that changed from the base of the PR and between 4fe6788 and c635783.

📒 Files selected for processing (11)
  • claude_code_log/cli.py
  • claude_code_log/converter.py
  • claude_code_log/html/renderer.py
  • claude_code_log/json/renderer.py
  • claude_code_log/markdown/renderer.py
  • claude_code_log/models.py
  • claude_code_log/renderer.py
  • dev-docs/application_model.md
  • dev-docs/messages.md
  • test/test_away_summary.py
  • test/test_detail_levels.py

Address review on #209: --no-recaps was missing from variant_suffix(), so a
--no-recaps export collided with the plain one on both the output filename and
the cache/path-existence key — the second invocation would be served the stale
prior variant (same class as the #165 no-timestamps fix).

Add no_recaps to variant_suffix() and thread it through every call site
(converter combined/paginated/individual/single-session/hierarchy, and the
html/markdown/json renderers). Unlike compact/no-timestamps (Markdown-only
formatting), --no-recaps filters messages, so it earns a suffix slot for ALL
formats, not just markdown. VARIANT_ENTRY_RE already matches the new segment.

Tests: variant_suffix no_recaps matrix (html/md/json + composition) and an
end-to-end test that the plain and --no-recaps exports land on distinct files.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cboos

cboos commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator Author

(Claude) Good catch on the variant/cache identity — confirmed and fixed in a0ef294.

--no-recaps was indeed missing from variant_suffix(), so a --no-recaps
export collided with the plain one on both the output filename and the
cache/path-existence key — the second run would be served the stale prior
variant (same class as the #165 no-timestamps fix).

Rather than decorating the suffix string at each call site, I added no_recaps
as a parameter to variant_suffix() and threaded it through every caller
(combined / paginated / individual-session / single-session / hierarchy in
converter.py, plus the html/markdown/json renderers). One difference from the
suggested patch: because --no-recaps filters messages (not formatting like
compact/no-timestamps, which are Markdown-only), it earns a suffix slot for
every format — html and json included, not gated on is_markdown.
VARIANT_ENTRY_RE already matches the new .no-recaps segment.

Tests added: a variant_suffix matrix for no_recaps across html/md/json (+
composition with detail/compact/no-timestamps), and an end-to-end test that the
plain and --no-recaps exports land on distinct files. just ci green.

@cboos cboos merged commit 0e478be into main Jun 7, 2026
17 checks passed
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.

Recaps always visible (except when --no-recaps)

1 participant