Skip to content

Conversation

@ShreeJejurikar
Copy link
Collaborator

@ShreeJejurikar ShreeJejurikar commented Dec 23, 2025

Related Issue

Closes #249

Summary

Implements an interactive command suggestion system with fuzzy search for Cortex.

Features

  • Interactive selection menu with arrow key navigation
  • Fuzzy search matching for package/command suggestions
  • Tab for details, Enter to install, q to quit
  • Context-aware suggestions (e.g., typing "Docker" shows docker-dev, docker-python, docker-nodejs, etc.)

Demo

cortex Docker
  docker-dev           Docker optimized for local development workflows
→ docker-python        Docker environment optimized for Python development
  docker-nodejs        Docker environment for Node.js applications
  docker-go            Docker environment for Go applications
  docker-testing       Docker setup for local testing and QA
  ↓ 5 more below
[↑↓ to select, Enter to install, Tab for details, q to quit]

Checklist

  • Tests pass (pytest tests/)
  • PR title format: [#249] Description
  • MVP label added if closing MVP issue

Summary by CodeRabbit

  • New Features

    • Added interactive package suggestion system with keyword-based matching and intent detection
    • Introduced demo command functionality
    • Enhanced CLI help display with quick-start command tips
    • New text-based interface for browsing and previewing packages with hardware detection
  • Removed

    • Stack and doctor commands from CLI surface
  • Changes

    • Simplified install command signature by removing parallel parameter

✏️ Tip: You can customize this high-level summary in your review settings.

Shree added 6 commits December 23, 2025 12:02
- Add SuggestionDatabase with 500+ curated package stacks
- Add IntentMatcher with fuzzy matching on keywords
- Add interactive TUI with scrolling viewport
- Integrate suggest() method in CLI
- Support 14 intents and 7 languages
- No LLM needed - works entirely offline
- Add JSON error handling with informative messages
- Specify UTF-8 encoding when opening JSON file
- Fix multi-word keyword matching to use word boundaries
- Remove unused imports (Text, detect_hardware)
- Fix misleading UI hints in non-interactive mode
- Fix error message to reference suggestions.json
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 23, 2025

Walkthrough

Introduces an interactive suggestion system for package discovery with fuzzy matching, intent detection, and hardware-aware filtering. Adds three new modules: SuggestionDatabase (JSON-backed suggestions data layer), IntentMatcher (intent and keyword-based stack ranking), and SuggestionTUI (interactive terminal UI with prompt_toolkit support). Updates CLI to route queries directly to suggestions workflow, removes the parallel parameter from install method signature, and integrates hardware detection for GPU-aware recommendations.

Changes

Cohort / File(s) Summary
CLI Entry Point
cortex/cli.py
Added suggest(query) method with interactive selection/confirmation workflow; added demo() method; modified install(software, execute, dry_run) signature (removed parallel parameter); removed stack() and doctor() public methods; updated main() to route early package queries to suggest() path; integrated early environment/suggestion flow with fallback to legacy behavior; updated help output with quick-tip line and removed stack/doctor rows
Suggestion Data Layer
cortex/database.py
New module: SuggestionDatabase class loads/indexes suggestions from JSON with intent, language, stack, package, and alias management; includes intent/language detection from keywords with alias resolution; filtering utilities (by intent, language, GPU vendor); package accessors; backward-compat alias PackageDatabase = SuggestionDatabase
Matching Engine
cortex/matcher.py
New module: IntentMatcher class for context-aware stack ranking; multi-layered scoring (exact ID, language+intent, keyword-based, fuzzy); keyword indexing; tokenization and normalization; GPU filtering and complexity bonuses; installation preview generation; backward-compat alias FuzzyMatcher = IntentMatcher
Interactive TUI
cortex/tui.py
New module: SuggestionTUI class with interactive UI via prompt_toolkit (search, keyboard navigation, preview rendering); run_suggestions(query, db_path, interactive) entry point selecting interactive/simple mode; print_suggestions(query, db_path, limit) scripting utility; hardware info display (CPU, RAM, GPU, disk); non-interactive fallback with rich tables
Test Updates
tests/test_cli.py, tests/test_cli_extended.py
Updated install call expectations in three tests to remove parallel=False argument, reflecting removal of parallel parameter from public install() signature

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as cortex/cli.py<br/>(CortexCLI.suggest)
    participant DB as cortex/database.py<br/>(SuggestionDatabase)
    participant Matcher as cortex/matcher.py<br/>(IntentMatcher)
    participant TUI as cortex/tui.py<br/>(SuggestionTUI)
    participant Hardware as Hardware<br/>Detection

    User->>CLI: suggest("docker")
    activate CLI
    
    CLI->>DB: Load suggestions from JSON
    activate DB
    DB->>DB: Build indexes (intents, stacks, languages)
    DB-->>CLI: SuggestionDatabase ready
    deactivate DB
    
    CLI->>TUI: Initialize with DB and Matcher
    activate TUI
    TUI->>Matcher: Create IntentMatcher(db)
    activate Matcher
    Matcher->>Matcher: Build keyword index from stacks
    Matcher-->>TUI: Matcher ready
    deactivate Matcher
    
    TUI->>Hardware: Detect GPU/CPU/RAM
    activate Hardware
    Hardware-->>TUI: Hardware info
    deactivate Hardware
    
    TUI->>Matcher: match("docker", limit=10)
    activate Matcher
    Matcher->>DB: detect_intent_from_keywords(tokens)
    Matcher->>DB: get_stacks_by_intent_and_language(...)
    Matcher->>Matcher: Score and rank results
    Matcher-->>TUI: Ranked stacks list
    deactivate Matcher
    
    Note over TUI: Interactive flow: render table,<br/>keyboard navigation (↑↓),<br/>Enter to select, Tab for preview
    TUI->>User: Display suggestions + navigate
    User->>TUI: Select stack (Enter)
    
    TUI->>Matcher: get_install_preview(selected_stack)
    activate Matcher
    Matcher->>DB: get_apt_packages_for_stack(...)
    Matcher->>DB: get_pip_packages_for_stack(...)
    Matcher-->>TUI: Preview with commands
    deactivate Matcher
    
    TUI->>User: Show install preview
    User->>TUI: Confirm (Enter)
    TUI->>CLI: Return selected item
    deactivate TUI
    
    CLI->>CLI: Execute install with selected stack
    deactivate CLI
    CLI-->>User: Install complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

enhancement, MVP

Suggested reviewers

  • mikejmorgan-ai

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title '[#249] Interactive command suggestions with fuzzy search' directly matches the main feature implemented in the PR and references the linked issue.
Description check ✅ Passed The description includes the required Related Issue section, provides a comprehensive summary of features, includes a demo, and has the checklist with tasks marked complete.
Linked Issues check ✅ Passed The PR implements all core requirements from issue #249: fuzzy matching, hardware-aware suggestions via SuggestionDatabase, common stacks, arrow key navigation via prompt_toolkit TUI, install preview generation, and offline-first operation without LLM dependency.
Out of Scope Changes check ✅ Passed All code changes directly support the interactive suggestions feature. Updates to CLI install signature (removing parallel parameter) are necessary refactorings to support the new workflow; test updates align with these signature changes.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@sonarqubecloud
Copy link

Copy link
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

🧹 Nitpick comments (4)
cortex/matcher.py (1)

354-386: Consider adding Args/Returns to the docstring.

The method works correctly, but the docstring could be more complete per coding guidelines requiring docstrings for public APIs.

🔎 Suggested docstring improvement
     def get_install_preview(self, item_type: str, item_id: str) -> dict:
-        """Get installation preview for a stack."""
+        """Get installation preview for a stack.
+
+        Args:
+            item_type: Type of item (e.g., "stack").
+            item_id: Identifier of the stack.
+
+        Returns:
+            Dictionary with installation details including packages,
+            commands, and metadata. Contains "error" key if stack not found.
+        """
cortex/database.py (1)

137-149: Consider using an index for get_intent and get_language.

These methods use linear search while get_stack and get_package use indexed lookup. If intent/language counts are small, this is acceptable, but adding indexes would be consistent.

cortex/cli.py (1)

166-168: Move imports to module level for consistency.

While inline imports work, moving subprocess and rich.progress imports to the top of the file is more consistent with PEP 8 style.

cortex/tui.py (1)

370-383: Consider reusing the database instance in CLI entry point.

Line 378 creates a new PackageDatabase() and FuzzyMatcher() when run_suggestions already used one. This is minor since it's only for the CLI test path.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 287a353 and a604e2b.

📒 Files selected for processing (7)
  • cortex/cli.py
  • cortex/database.py
  • cortex/matcher.py
  • cortex/tui.py
  • data/suggestions.json
  • tests/test_cli.py
  • tests/test_cli_extended.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs

Files:

  • tests/test_cli.py
  • cortex/matcher.py
  • cortex/cli.py
  • cortex/tui.py
  • cortex/database.py
  • tests/test_cli_extended.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Maintain >80% test coverage for pull requests

Files:

  • tests/test_cli.py
  • tests/test_cli_extended.py
🧠 Learnings (1)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Implement audit logging to ~/.cortex/history.db for all package operations

Applied to files:

  • cortex/cli.py
🧬 Code graph analysis (4)
tests/test_cli.py (1)
cortex/cli.py (1)
  • main (721-874)
cortex/matcher.py (1)
cortex/database.py (8)
  • stacks (121-123)
  • detect_language_from_keywords (219-224)
  • detect_intent_from_keywords (161-217)
  • intents (111-113)
  • get_stack (151-153)
  • get_stacks_by_intent_and_language (236-241)
  • get_stacks_by_language (232-234)
  • get_stacks_by_intent (228-230)
cortex/cli.py (4)
cortex/tui.py (1)
  • run_suggestions (319-345)
cortex/database.py (2)
  • SuggestionDatabase (11-283)
  • packages (126-128)
cortex/matcher.py (2)
  • IntentMatcher (26-386)
  • get_install_preview (354-386)
cortex/validators.py (1)
  • validate_install_request (117-144)
cortex/tui.py (1)
cortex/matcher.py (2)
  • match (202-352)
  • get_install_preview (354-386)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build Package
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.10)
🔇 Additional comments (39)
cortex/matcher.py (7)

1-24: LGTM! Module docstring and imports are well-structured.

The module docstring clearly explains the matching strategy with examples. Imports are appropriate.


26-71: LGTM! Well-documented scoring constants and stop words.

The class docstring clearly explains the scoring priority, and constants are appropriately defined at the class level.


73-103: LGTM! Initialization and keyword indexing are well-implemented.

The __init__ has proper docstring with Args section, and _build_keyword_index correctly builds a reverse index from keywords to stacks.


105-136: LGTM! Tokenization and context detection are well-implemented.

The methods correctly handle query normalization and multi-word keyword matching.


138-168: LGTM! Keyword scoring logic is sensible.

The scoring hierarchy (exact > partial > name > description) is appropriate for relevance ranking.


202-352: LGTM! Comprehensive matching logic with multiple strategies.

The method correctly implements the documented scoring priority with appropriate hardware-aware filtering and bonus scoring.


389-390: LGTM! Backward compatibility alias is appropriate.

The alias allows existing code referencing FuzzyMatcher to continue working.

cortex/database.py (9)

1-10: LGTM! Module docstring and imports are appropriate.

The module clearly states its purpose. Imports are minimal and appropriate.


11-38: LGTM! Class and initialization are well-structured.

The class docstring clearly explains the database structure, and initialization flow is correct.


40-54: LGTM! Database discovery with sensible fallback paths.

The search order from project-relative to system-wide paths is appropriate, with backward compatibility for packages.json.


56-70: LGTM! Robust JSON loading with helpful error messages.

The error handling includes file path, error message, and line number for debugging.


72-106: LGTM! Efficient index building for fast lookups.

The indexing strategy enables O(1) lookups for stacks by ID, intent, and language.


108-133: LGTM! Properties are clean and well-documented.


161-217: LGTM! Thoughtful multi-pass intent detection with clear priority.

The six-pass approach correctly handles ambiguity between intent keywords and language keywords, prioritizing more specific matches.


226-249: LGTM! Filtering methods are efficient and correct.

The intersection logic for get_stacks_by_intent_and_language correctly uses set operations.


251-287: LGTM! Package methods and backward compatibility aliases are well-designed.

The aliases ensure smooth migration from older API usage.

tests/test_cli_extended.py (3)

283-283: LGTM! Test assertion updated to match new API signature.

Correctly removes the parallel parameter from the expected call.


291-291: LGTM! Test assertion updated to match new API signature.


299-299: LGTM! Test assertion updated to match new API signature.

tests/test_cli.py (3)

187-187: LGTM! Test assertion updated to match new API signature.


195-195: LGTM! Test assertion updated to match new API signature.


203-203: LGTM! Test assertion updated to match new API signature.

cortex/cli.py (8)

7-12: Logging suppression and path modification look reasonable.

Suppressing noisy logs and adding parent directory to path for imports is acceptable for CLI tooling.


31-38: LGTM! Graceful degradation for optional suggestion system.

The try/except pattern allows the CLI to function even without the suggestion modules.


304-305: LGTM! API signature updated with clear docstring.

The parallel parameter removal is reflected in tests. The docstring accurately describes the new behavior.


665-671: Demo method is a minimal placeholder.

The comment indicates existing demo logic should be preserved. Verify this is intentional or if more functionality should be added.


721-755: LGTM! Smart early routing for suggestion queries.

The approach of intercepting queries before argparse avoids "unrecognized command" errors for natural language input like cortex docker.


683-683: LGTM! Helpful quick tip added to help output.


849-849: LGTM! Install call updated to match new signature.


189-201: Add installation history logging to the suggest() method.

The suggest() method executes installation commands (lines 189-201) but does not record them to the installation history database, unlike the install() method. To maintain a complete audit trail of all package operations, instantiate InstallationHistory, extract packages from the commands, and call record_installation() after successful execution, similar to how it's done in the install() method (lines 313, 353).

⛔ Skipped due to learnings
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Implement audit logging to ~/.cortex/history.db for all package operations
cortex/tui.py (9)

1-17: LGTM! Module setup with appropriate imports.

The docstring clearly identifies the module purpose. Imports are minimal and appropriate.


20-33: LGTM! Class initialization is well-structured.

The class has a proper docstring with Args section and appropriate type hints.


35-80: LGTM! Search and rendering logic is clean.

The methods have proper docstrings and type hints. The rendering correctly handles empty results and selection highlighting.


82-109: LGTM! Preview rendering with appropriate truncation.

The method handles the no-selection case gracefully and limits displayed packages to avoid overwhelming the UI.


195-247: LGTM! Scrolling viewport and display logic are well-implemented.

The scroll indicators and viewport calculations are correct.


253-287: LGTM! Full details display is comprehensive and clean.


289-316: LGTM! Simple mode provides a clean fallback.

The method handles both invalid input and keyboard interrupts gracefully.


319-345: LGTM! Entry point function with proper error handling and documentation.


348-367: LGTM! Scripting-friendly function with error handling.

Comment on lines +170 to +200
def _fuzzy_match(self, query: str, target: str) -> float:
"""
Simple fuzzy matching score.
Returns value between 0 and 1.
"""
if not query or not target:
return 0.0

query = query.lower()
target = target.lower()

if query == target:
return 1.0

if query in target or target in query:
return 0.8

# Check if query is a prefix
if target.startswith(query):
return 0.9

# Character overlap score
query_chars = set(query)
target_chars = set(target)
overlap = len(query_chars & target_chars)
total = len(query_chars | target_chars)

if total == 0:
return 0.0

return overlap / total * 0.5
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Prefix matching is unreachable due to condition ordering.

The prefix check at line 188 (target.startswith(query)) will never be reached because a prefix is also a substring, and the substring check at line 184 (query in target) returns 0.8 first. If prefix matching should score higher (0.9), reorder the conditions.

🔎 Proposed fix
         if query == target:
             return 1.0
 
+        # Check if query is a prefix (more specific than substring)
+        if target.startswith(query):
+            return 0.9
+
         if query in target or target in query:
             return 0.8
 
-        # Check if query is a prefix
-        if target.startswith(query):
-            return 0.9
-
         # Character overlap score
🤖 Prompt for AI Agents
In cortex/matcher.py around lines 170 to 200, the prefix check
target.startswith(query) is unreachable because the earlier substring check
(query in target or target in query) matches prefixes first and returns 0.8;
move the prefix check above the generic substring check so exact-prefix matches
return 0.9, keeping the exact-equality check at the top and leaving the rest of
the fallback logic unchanged.

Comment on lines +180 to +185
@kb.add("tab")
def _(event):
event.app.exit()
self.show_full_details()
# Restart the app
event.app.run()
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Tab handler may not work as intended after exit.

Calling event.app.exit() followed by event.app.run() within the same key binding handler has undefined behavior. The run() call at line 185 occurs after the app has already exited, so it likely won't restart the interactive session properly.

🔎 Consider restructuring the Tab flow

One approach is to use a loop outside the app or set a flag to indicate "show details and restart":

# In run_interactive, use a loop pattern:
while True:
    app.run()
    if self.show_details_requested:
        self.show_full_details()
        self.show_details_requested = False
        continue
    break
🤖 Prompt for AI Agents
In cortex/tui.py around lines 180-185, the Tab key handler currently calls
event.app.exit() and then event.app.run() which is undefined; instead set a flag
(e.g. self.show_details_requested = True) in the handler and only call
event.app.exit(), removing the direct run() call. Then restructure the outer
run_interactive loop to repeatedly call app.run(), check the flag after run
returns, call self.show_full_details() when the flag is set, clear the flag, and
continue the loop to restart the UI; this ensures exiting and restarting are
coordinated outside the key-binding handler.

@Suyashd999
Copy link
Collaborator

@ShreeJejurikar
1. not navigable using arrows

Image

2. show installation plan /dry run before confirmation

Image

@Suyashd999 Suyashd999 self-requested a review December 23, 2025 19:17
@Suyashd999
Copy link
Collaborator

closed because it is redundant

@Suyashd999 Suyashd999 closed this Dec 24, 2025
@Sahilbhatane
Copy link
Collaborator

Approved checked after discussion

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.

[MVP] Interactive command suggestions with fuzzy search

4 participants