Skip to content

🎨 Palette: Add persistent CLI status indicator#65

Open
Whamp wants to merge 1 commit intomainfrom
palette-add-status-indicator-15023239142878418116
Open

🎨 Palette: Add persistent CLI status indicator#65
Whamp wants to merge 1 commit intomainfrom
palette-add-status-indicator-15023239142878418116

Conversation

@Whamp
Copy link
Owner

@Whamp Whamp commented Feb 6, 2026

User description

💡 What: Added a persistent status indicator to the CLI using rich library.
🎯 Why: To provide immediate visual feedback (Ready, Recording, Transcribing) to the user, improving the UX over scrolling logs.
📸 Before/After: Before was just logs. After has a spinner at the bottom showing current state.
♿ Accessibility: Provides clear state indication.


PR created automatically by Jules for task 15023239142878418116 started by @Whamp


PR Type

Enhancement


Description

  • Add persistent CLI status indicator using rich.console.Status

  • Update status during recording and transcribing lifecycle events

  • Display "Ready", "Recording...", and "Transcribing..." states

  • Add comprehensive tests for status indicator updates


Diagram Walkthrough

flowchart LR
  A["ChirpApp Init"] -- "Create status_indicator" --> B["Status: Ready"]
  C["Start Recording"] -- "update status" --> D["Status: Recording"]
  D -- "Stop Recording" --> E["Status: Transcribing"]
  E -- "Transcription Complete" --> B
  F["Keyboard Interrupt"] -- "stop indicator" --> G["Exit"]
Loading

File Walkthrough

Relevant files
Enhancement
main.py
Implement persistent status indicator lifecycle                   

src/chirp/main.py

  • Store console instance and initialize status_indicator in __init__
  • Start status indicator in run() method and stop on keyboard interrupt
  • Update status to "Recording..." when audio capture begins
  • Update status to "Transcribing..." when recording stops
  • Reset status to "Ready" after transcription completes in finally block
  • Refactor _transcribe_and_inject with try-finally for proper cleanup
+28/-17 
Tests
test_ui_ux.py
Add UI/UX tests for status indicator                                         

tests/test_ui_ux.py

  • Create new test file for UI/UX functionality
  • Mock all external dependencies (sounddevice, winsound,
    ParakeetManager, etc.)
  • Test status indicator updates during recording start, stop, and
    transcription
  • Verify status transitions from "Recording..." to "Transcribing..." to
    "Ready"
  • Mock executor to prevent background task execution during tests
+80/-0   
Documentation
palette.md
Record learning from status indicator implementation         

.jules/palette.md

  • Document learning about visual feedback vs log messages discrepancy
  • Record insight that persistent state indicators are superior to
    scrolling logs
  • Capture action item to verify features in code before assuming
    existence
+5/-0     

- Add `self.status_indicator` to `ChirpApp` using `rich.console.Status`.
- Update status during recording and transcribing lifecycle.
- Add `tests/test_ui_ux.py` to verify status updates.
- Create `.jules/palette.md` to record learning.

Co-authored-by: Whamp <1115485+Whamp@users.noreply.github.com>
@google-labs-jules
Copy link
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@qodo-code-review
Copy link

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Sensitive data logged: The PR logs the full transcription text via self.logger.debug("Transcription:
%s", text), which can leak potentially sensitive user content into logs.

Referred Code
self.logger.debug("Transcription finished in %.2fs (chars=%s)", duration, len(text))
if not text.strip():
    self.logger.info("Transcription empty; skipping paste")
    return
self.logger.debug("Transcription: %s", text)
self.text_injector.inject(text)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Audit scope unclear: The PR adds new runtime state transitions (recording/transcribing) but does not clarify
whether these constitute "critical actions" requiring audit fields like user ID
and outcome, which cannot be verified from the diff alone.

Referred Code
def run(self) -> None:
    try:
        self._register_hotkey()
        self.logger.info("Chirp ready. Toggle recording with %s", self.config.primary_shortcut)
        self.status_indicator.start()
        self.keyboard.wait()
    except KeyboardInterrupt:
        self.status_indicator.stop()
        self.logger.info("Interrupted, exiting.")

def _register_hotkey(self) -> None:
    self.logger.debug("Registering hotkey: %s", self.config.primary_shortcut)
    try:
        self.keyboard.register(self.config.primary_shortcut, self.toggle_recording)
    except Exception:
        self.logger.error("Unable to register primary shortcut. Run as Administrator on Windows.")
        raise

def toggle_recording(self) -> None:
    with self._lock:
        if not self._recording:


 ... (clipped 63 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix race condition in status updates

Fix a race condition by introducing a counter for active transcription tasks,
ensuring the status indicator only resets to "Ready" after all tasks are
complete.

src/chirp/main.py [158-178]

 class ChirpApp:
     def __init__(self, *, verbose: bool = False) -> None:
+        ...
+        self._transcription_tasks = 0
+        self._transcription_lock = threading.Lock()
 ...
     def _stop_recording(self) -> None:
 ...
         self.status_indicator.update("[bold green]Transcribing...[/bold green]", spinner="dots")
         self.logger.info("Recording stopped (%s samples)", waveform.size)
+        with self._transcription_lock:
+            self._transcription_tasks += 1
         self._executor.submit(self._transcribe_and_inject, waveform)
 
     def _transcribe_and_inject(self, waveform) -> None:
         try:
 ...
         finally:
-            if not self._recording:
-                self.status_indicator.update("Ready", spinner="dots")
+            with self._transcription_lock:
+                self._transcription_tasks -= 1
+                if self._transcription_tasks == 0 and not self._recording:
+                    self.status_indicator.update("Ready", spinner="dots")

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies and fixes a race condition in the new status indicator logic, preventing misleading UI feedback when multiple transcriptions are active concurrently.

High
Always stop status on exit

Move self.status_indicator.stop() into a finally block within the run method to
guarantee it is always called on application exit.

src/chirp/main.py [102-104]

 except KeyboardInterrupt:
+    self.logger.info("Interrupted, exiting.")
+finally:
     self.status_indicator.stop()
-    self.logger.info("Interrupted, exiting.")
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: This is a good suggestion for robust cleanup, ensuring the status_indicator is always stopped on exit, not just on a KeyboardInterrupt.

Medium
  • More

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant