gemini-cli - ✅(Solved) Fix Add `/rewind --to <user-message-index>` for use in orchestrated workflows [3 pull requests, 2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
google-gemini/gemini-cli#24933Fetched 2026-04-09 08:17:11
View on GitHub
Comments
2
Participants
2
Timeline
12
Reactions
0
Timeline (top)
labeled ×4commented ×2unlabeled ×2issue_type_added ×1

Error Message

// can return a clear error instead of silently falling through to return { type: 'message', messageType: 'error', return { type: 'message', messageType: 'error',

PR fix notes

PR #25068: feat(cli): add positional argument support to /rewind command

Description (problem / solution / changelog)

Closes #24933

Summary

Add support for /rewind <index> with Python-style indexing, enabling stdin-driven orchestrators to rewind conversations without navigating the TUI.

  • /rewind 1 — rewind to before user message 1 (0-indexed)
  • /rewind -1 — rewind to before the last user message
  • /rewind (no args) — existing TUI behavior, unchanged

How it works

Uses the same conversation.messages.filter(msg => msg.type === 'user') derivation that RewindViewer already uses internally (lines 71-74) to resolve the index to a message ID, then calls the existing rewindConversation helper. No changes to the shared helper or the TUI path.

Testing

  • 8 new tests covering positive/negative indexing, edge cases, and error handling
  • 5 existing guard-check tests updated to async (required since the action is now async)
  • All 21 tests pass, npm run preflight clean

Changed files

  • packages/cli/src/ui/commands/rewindCommand.test.tsx (modified, +81/-10)
  • packages/cli/src/ui/commands/rewindCommand.tsx (modified, +66/-3)

PR #25150: feat(cli): Add /rewind <N> index argument for non-interactive use

Description (problem / solution / changelog)

Summary

<!-- Concisely describe what this PR changes and why. Focus on impact and urgency. -->

Adds support for an optional [index] argument to the /rewind command. This allows external tools orchestrating the CLI to trim conversation history programmatically, maintaining prompt cache efficiency without needing to navigate the TUI. This PR also addresses internal code duplication by centralizing string manipulation utilities.

Details

<!-- Add any extra context and design decisions. Keep it brief but complete. -->
  • Indexing: Supports 0-based indexing and Python-style negative indexing (e.g., /rewind -1 for the last message).
  • Buffer handling: Properly restores the cleaned prompt text back into the input buffer.
  • Refactoring: Centralized getCleanedRewindText() in formatters.ts to ensure consistent string padding across all rewind paths.
  • Error handling: rewindConversation() now returns a boolean to prevent displaying a success message when rewind fails.
  • Files Modified:
    • packages/cli/src/ui/commands/rewindCommand.tsx
    • packages/cli/src/ui/commands/rewindCommand.test.tsx
    • packages/cli/src/ui/components/RewindViewer.tsx
    • packages/cli/src/ui/utils/formatters.ts
    • docs/cli/rewind.md

Related Issues

<!-- Use keywords to auto-close issues (Closes #123, Fixes #456). If this PR is only related to an issue or is a partial fix, simply reference the issue number without a keyword (Related to #123). -->

Closes #24933

How to Validate

<!-- List exact steps for reviewers to validate the change. Include commands, expected results, and edge cases. -->
  1. Start Gemini CLI and send a few prompts.
  2. Enter /rewind -1 to delete the last user message and its response.
  3. Verify the chat history trims successfully and your input prompt restores the rewound text.
  4. Run the unit tests locally:
    npm test -w @google/gemini-cli -- src/ui/commands/rewindCommand.test.tsx
  5. Verify the full preflight suite passes:
    npm run preflight

Pre-Merge Checklist

<!-- Check all that apply before requesting review or merging. -->
  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

Changed files

  • docs/cli/rewind.md (modified, +25/-0)
  • packages/cli/src/ui/commands/rewindCommand.test.tsx (modified, +118/-10)
  • packages/cli/src/ui/commands/rewindCommand.tsx (modified, +61/-4)
  • packages/cli/src/ui/components/RewindViewer.tsx (modified, +1/-9)
  • packages/cli/src/ui/utils/formatters.ts (modified, +13/-0)

PR #21880: feat(workflows): give authors of issues an option toward assignment priority

Description (problem / solution / changelog)

Summary

<!-- Concisely describe what this PR changes and why. Focus on impact and urgency. -->

When filing an issue many community members spend time and effort scoping out what changes are needed and why. Unfortunately, this results in a situation where the hard work of filing the issue is not met with being able to land the change when another community member self assigns as soon as the issue is labeled help wanted. Too often maintainers have to play referee and re assign the issue to the author (this should only happen every now and then!)

ML Flow and Apache Iceberg are examples of repos that have this. I'm sure there are more!

This PR also adds a small clause that steers contributors toward checking out the larger context of an issue before proceeding with a PR. Joining an existing discussion or supporting an existing PR can make the review process easier.

Both of these changes have the primary goal of making it easier to land changes and making it easier to review changes.

Details

<!-- Add any extra context and design decisions. Keep it brief but complete. -->

Issue Templates

For bugs and features, contributors can now mark that they intend to contribute toward this issue if it is approved.

Assignment Workflows

For issue authors who do mark their intention to contribute the following logic is intended:

  • Once the issue is filed, gemini cli bot will notify the issue author if they already have three issues assigned, giving them time to prepare for if and when the issue is labeled help wanted
  • Once the issue is labeled help wanted by a maintainer, gemini cli bot will try to assign the issue to the author!
  • Manual assignment logic is retained within the bounds of this new workflow

For issue authors who do not mark an intention to contribute, things should remain the same. It's then up to anybody else to assign themselves once the issue is marked help wanted

Related Issues

<!-- Use keywords to auto-close issues (Closes #123, Fixes #456). If this PR is only related to an issue or is a partial fix, simply reference the issue number without a keyword (Related to #123). -->

Closes #21718

How to Validate

<!-- List exact steps for reviewers to validate the change. Include commands, expected results, and edge cases. -->

Pre-Merge Checklist

<!-- Check all that apply before requesting review or merging. -->
  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

Changed files

  • .github/ISSUE_TEMPLATE/bug_report.yml (modified, +7/-0)
  • .github/ISSUE_TEMPLATE/feature_request.yml (modified, +7/-0)
  • .github/workflows/gemini-issue-assignment.yml (added, +154/-0)
  • .github/workflows/gemini-self-assign-issue.yml (removed, +0/-150)
  • CONTRIBUTING.md (modified, +31/-11)

Code Example

// Inside rewindCommand.action, after the existing guard checks:

  const argTrimmed = args?.trim() ?? '';
  if (argTrimmed) {
    // Match `--to <N>` or `--to=<N>`. Captures negative integers so we
    // can return a clear error instead of silently falling through to
    // the TUI on malformed input.
    const toMatch = argTrimmed.match(/^--to(?:\s+|=)(-?\d+)$/);
    if (!toMatch) {
      return { type: 'message', messageType: 'error',
               content: `Unrecognized arguments. Usage: /rewind --to <user-message-index>` };
    }

    const index = parseInt(toMatch[1], 10);

    const userMessages = conversation.messages.filter(m => m.role === 'user');
    if (isNaN(index) || index < 0 || index >= userMessages.length) {
      return { type: 'message', messageType: 'error',
               content: `Invalid index. --to requires a valid user message index (0 to ${Math.max(0, userMessages.length - 1)}).` };
    }

    // rewindTo is exclusive — user message at `index` is removed along
    // with everything after it.
    await rewindConversation(context, client, recordingService, userMessages[index].id, '');
    return { type: 'message', messageType: 'info',
             content: `Rewound to before user message ${index}.` };
  }

  // Existing path: no args → return the TUI
  return { type: 'custom_dialog', component: <RewindViewer ... /> };
RAW_BUFFERClick to expand / collapse

What would you like to be added?

Add support for a --to <user-message-index> flag to /rewind. When invoked as /rewind --to <N>, the command rewinds the conversation to the state just before the Nth user message (0-indexed) was sent — non-interactively, calling the existing rewindConversation() helper directly and returning a {type: 'message', ...} result instead of mounting the RewindViewer dialog. When invoked with no arguments, behavior is unchanged — the TUI opens as today.

This is a tiny change that lets an external process driving the CLI via stdin do what /rewind already does manually: trim the conversation while keeping the cached prefix intact. The helper, the guard checks, and the action's branching pattern all already exist — this just adds one more branch at the top.

Why is this needed?

Prompt cache preservation

The Gemini API charges roughly double for input above the 200K-token threshold on Pro-tier models.

For any long-running workflow that loads substantial context documents at session start, staying under 200K is the difference between sustainable cost and prohibitive cost. Session-start documents are typically the largest single chunk of context and are exactly what the prompt-caching layer is designed for .

/rewind is currently the only slash command that trims the conversation while keeping the cached prefix intact. The other options all destroy the front of the history outright:

  • /clear removes all messages, including the loaded session-start documents. The documents themselves are gone — they have to be re-uploaded next cycle, cache cold.
  • /compress rewrites the prefix into a summary, which discards the original messages entirely. Same effect: documents gone, cache invalidated.

So /rewind is the right operation for orchestrated cyclic workflows.

The only thing wrong with it is that it's only accessible through a TUI dialog (RewindViewer / RewindConfirmation in packages/cli/src/ui/components/), which an external process driving the CLI via stdin cannot navigate.


My orchestrated multi-cycle review workflow

I run an orchestrator (built around pexpect) that wraps the Gemini CLI for a multi-cycle review workflow:

  1. Session start. I load context documents — frameworks, architecture references, decision logs, etc. These are large (often hundreds of KB), stay constant for the entire run, and are exactly what should sit in the prompt cache.
  2. Cycle. I paste the current state of the dynamic documents (the artifact under review, plus any frequently-updated supporting docs), ask Gemini for a review, receive findings.
  3. Apply fixes outside the Gemini session.
  4. Trim the conversation back to the post-static-docs state so the next cycle starts from the same cached prefix and the conversation doesn't grow unbounded.
  5. Loop. Paste the next iteration of the dynamic documents, ask for review, receive findings, trim, repeat.

I currently run this loop manually, using /rewind between cycles to trim. It keeps total per-cycle context just under the 200K-token threshold, the static prefix stays cached, and per-cycle cost stays flat — it works, but I can't leave the loop unattended.

I previously had this fully automated by having my orchestrator kill and respawn the Gemini CLI between cycles, but re-uploading the session-start documents (hundreds of KB) every time made it prohibitively expensive — the cache went cold on every cycle and per-cycle input cost climbed past the 200K threshold fast. So I switched back to running /rewind manually after every review. The TUI-only /rewind is the only existing operation that trims the conversation while preserving the cached prefix; what's missing is a way to invoke it from stdin. The proposal in the additional context section closes that gap.

Additional context

Proposed solution

Add a --to <user-message-index> flag to /rewind:

/rewind (no change — opens the RewindViewer TUI as today) /rewind --to Non-interactive: rewind to the Nth user message (0-indexed)

The user-message index matches the unit RewindViewer already uses to present rewind targets — only user messages are valid rewind points in the existing TUI, so the same indexing applies in the non-interactive mode. An orchestrator that loaded context documents at user message 0 will typically rewind with --to 1 on every cycle, dropping the most recent review exchange while preserving the cached prefix at message 0. We use a --to flag rather than a positional argument to keep orchestrator logs self-documenting and to leave the namespace open for future flags (like --revert-files).

Boundary semantics (--to N is exclusive)

--to <N> matches the existing ChatRecordingService.rewindTo() contract: user message N and everything after it are removed. The conversation is left in the state it was in just before user message N was sent. This is the same semantic the existing RewindViewer TUI uses today — selecting a message and confirming removes that message and everything from that point onward. The index is 0-indexed to match standard array offsets, since orchestration scripts work natively with this convention.

Concrete example. Suppose user message 0 contains your loaded session-start documents, and user message 1 contains a review request. To remove the review request (and the assistant's response to it) while preserving the loaded documents, run:

/rewind --to 1

This removes user message 1 and everything after, leaving the conversation at user message 0 + its assistant response — exactly the cached prefix the orchestrator wants to return to before pasting the next cycle's dynamic documents.

The exclusive semantic comes directly from the existing rewindTo() implementation in packages/core/src/services/chatRecordingService.ts; the non-interactive branch reuses it without modification, so the contract is automatically consistent with /rewind's TUI behavior. The non-interactive mode defaults to history-only — disk-side file revert (RewindOutcome.RewindAndRevert / RevertOnly) remains TUI-only, since it requires interactive confirmation. If non-interactive file revert becomes useful later, it can be added as a separate flag (e.g., --revert-files) in a follow-up.


Implementation pseudocode

The change slots cleanly into the top of rewindCommand.action in packages/cli/src/ui/commands/rewindCommand.tsx, reusing the existing rewindConversation helper before the RewindViewer dialog is ever mounted. No new files or command registrations are needed. Estimated diff: ~15–25 lines plus a unit test in the existing rewindCommand.test.tsx.

// Inside rewindCommand.action, after the existing guard checks:

const argTrimmed = args?.trim() ?? '';
if (argTrimmed) {
  // Match `--to <N>` or `--to=<N>`. Captures negative integers so we
  // can return a clear error instead of silently falling through to
  // the TUI on malformed input.
  const toMatch = argTrimmed.match(/^--to(?:\s+|=)(-?\d+)$/);
  if (!toMatch) {
    return { type: 'message', messageType: 'error',
             content: `Unrecognized arguments. Usage: /rewind --to <user-message-index>` };
  }

  const index = parseInt(toMatch[1], 10);

  const userMessages = conversation.messages.filter(m => m.role === 'user');
  if (isNaN(index) || index < 0 || index >= userMessages.length) {
    return { type: 'message', messageType: 'error',
             content: `Invalid index. --to requires a valid user message index (0 to ${Math.max(0, userMessages.length - 1)}).` };
  }

  // rewindTo is exclusive — user message at `index` is removed along
  // with everything after it.
  await rewindConversation(context, client, recordingService, userMessages[index].id, '');
  return { type: 'message', messageType: 'info',
           content: `Rewound to before user message ${index}.` };
}

// Existing path: no args → return the TUI
return { type: 'custom_dialog', component: <RewindViewer ... /> };

This is a strictly additive extension. It does not alter existing interactive /rewind behavior, the SlashCommand interface, or perform non-interactive disk side-effects (file reversion remains TUI-only).


Related issues

  • #21891 — Stale Output Elision (History Pruning) (open) — proposes automatic heuristic-based pruning. Complementary, not duplicative. The proposal here is the deterministic, user-driven primitive that automation could be built on top of.
  • #16955 — [Context Mgmt] Rolling Tool Output Pruning (closed) — proposed an automatic rolling window. Different problem (heuristic vs explicit, stale-output detection vs deterministic rewind point).

This proposal is the non-interactive equivalent of an operation /rewind already performs flawlessly through its TUI. It's the same relationship sed has to a text editor — same domain, different access pattern, both needed for different kinds of users.


Willing to PR

Happy to submit a pull request. The change is small, strictly additive, and uses the existing helpers and patterns.

extent analysis

TL;DR

To fix the issue, add a --to <user-message-index> flag to the /rewind command, allowing non-interactive rewinding to a specific user message index.

Guidance

  • Implement the proposed solution by adding a --to flag to the /rewind command, which takes a user message index as an argument.
  • Update the rewindCommand.action function to parse the --to flag and call the rewindConversation helper with the specified user message index.
  • Add error handling for invalid indices and unrecognized arguments.
  • Ensure the non-interactive mode defaults to history-only and does not perform disk-side file reversion.

Example

const argTrimmed = args?.trim() ?? '';
if (argTrimmed) {
  const toMatch = argTrimmed.match(/^--to(?:\s+|=)(-?\d+)$/);
  if (!toMatch) {
    return { type: 'message', messageType: 'error', content: `Unrecognized arguments. Usage: /rewind --to <user-message-index>` };
  }

  const index = parseInt(toMatch[1], 10);
  // ...
}

Notes

The proposed solution is a strictly additive extension that does not alter existing interactive /rewind behavior. It provides a non-interactive equivalent of an operation /rewind already performs through its TUI.

Recommendation

Apply the proposed workaround by adding the --to flag to the /rewind command, as it provides a deterministic, user-driven primitive for rewinding the conversation to a specific user message index.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

gemini-cli - ✅(Solved) Fix Add `/rewind --to <user-message-index>` for use in orchestrated workflows [3 pull requests, 2 comments, 2 participants]