Skip to content

Conversation

@Kesavaraja67
Copy link
Contributor

@Kesavaraja67 Kesavaraja67 commented Jan 7, 2026

Related Issue

Closes #119

Summary

This PR implements a robust System Role Management architecture, enabling Cortex to dynamically adapt to a machine's "personality" (e.g., ML Workstation, Web Server). It replaces static configurations with an AI-driven sensing layer, a privacy-hardened shell history parser, and a persistent local learning feedback loop.

Key Features

  • Privacy-Hardened Activity Sensing
    • Intent-Based Tokenization: Maps known technical tools (e.g., git, docker) to intent signals while masking unknown or long script names as intent:unknown to prevent filename leaks.
    • PII Redaction: Utilizes precompiled regex patterns to scrub API keys, tokens, and credentials from shell history before AI analysis.
    • Path Anonymization: Normalizes both Linux and Windows separators and extracts only command basenames to prevent absolute path leakage.
  • Deterministic Cross-Platform Locking
    • Byte-Range Precision: Implements msvcrt locking on Windows with mandatory seek(0) calls to target a stable 1-byte region, ensuring deterministic locking.
    • POSIX Advisory Locking: Utilizes fcntl.flock for robust concurrency control on Unix-based systems.
  • Audit-Compliant Persistence
    • Role Transition Logging: Automatically records every role change in ~/.cortex/history.db, capturing the timestamp, configuration key, previous value, and new value.
    • "Last-One-Wins" Semantics: Targets only the final occurrence of a key in configuration files, preserving user-defined formatting, export prefixes, and inline comments.
  • Chronological Learning Loop
    • Recency-First Extraction: Parses the installation database to identify successful package history, prioritizing the most recent unique installations for AI context.
    • JSON Schema Support: Correctly extracts package arrays from serialized JSON data within the SQLite history layer.
  • Hermetic Test Isolation
    • Zero-Leakage Fixtures: Implements a temp_cortex_dir and role_manager fixture suite that isolates all file I/O and database operations from the real user home directory.
    • Comprehensive Coverage: Verified 100% pass rate for 20 specialized tests, achieving 86.63% coverage.

Demo

Video.Project.5.1.mp4

AI Disclosure

  • No AI used
  • AI/IDE/Agents used

Used Gemini 3 Flash as a Capable AI Thought Partner to:

  1. Architect the RoleManager sensing logic and privacy-hardening filters.
  2. Implement thread-safe, cross-platform file locking with seek(0) precision.
  3. Develop the pytest suite to validate audit logging and "Last-One-Wins" formatting preservation.

Checklist

  • Tests Pass: Verified 20/20 pass rate with pytest tests/test_role_management.py.
  • High Coverage: Achieved 86.63% coverage, exceeding the 80% bounty requirement.
  • Linting: Passed ruff check (with no undefined variables) and black formatting.
  • Audit Logging: Verified role transitions are recorded in history.db.
  • Privacy Verified: Confirmed sensitive filenames are masked in shell history.
  • Documentation: Updated README.md and added role-specific documentation.

Summary by CodeRabbit

  • New Features

    • AI-driven System Roles: automatic role detection, GPU-aware sensing, learned install patterns, persisted role state, and tailored package recommendations.
  • CLI

    • New role commands: detect and set — auto-detect system role or manually set it; rich Markdown output and help integration.
  • Documentation

    • New Role Management guide; README and project status updated; minor diagram formatting tweaks.
  • Tests

    • Extensive test coverage for sensing, redaction, persistence, concurrency, cross-platform locking, and edge cases.
  • Other

    • Added new installation type for future config tracking.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 7, 2026

📝 Walkthrough

Walkthrough

Adds a new RoleManager for sensing, redacting, and persisting system roles; integrates cortex role detect and cortex role set CLI commands that invoke AI recommendations; introduces docs/ROLES.md; extends InstallationType with CONFIG; and adds comprehensive tests for sensing, persistence, redaction, and cross-platform locking.

Changes

Cohort / File(s) Summary
Core Role Management
cortex/role_manager.py
New RoleManager and SystemContext TypedDict: probes PATH binaries, detects GPUs, extracts privacy‑preserving shell-history intents and learned install patterns, exposes get_system_context(), save_role(), get_saved_role(), and implements atomic _locked_read_modify_write() with POSIX/Windows locking and input validation.
CLI Integration
cortex/cli.py
Imports RoleManager; adds role command group with detect and set <role_slug> subcommands; new CortexCLI.role() method to sense context, persist roles, build AI prompts, render Markdown responses, log install history, and wiring in main() and help output.
Documentation
README.md, docs/ROLES.md
README updated to list Role Management in features; new docs/ROLES.md documents detection and manual role setting, usage examples, persistence semantics (atomic swap/locking), privacy/redaction approach, and implementation notes.
Tests
tests/test_role_management.py
New pytest suite with hermetic fixtures covering context gathering, redaction, learned patterns, save/get parsing/formatting, atomic write/locking behaviors (POSIX/Windows), concurrency, opt-outs, corrupted histories, and edge cases.
Installation History Enum
cortex/installation_history.py
Added CONFIG = "config" member to InstallationType enum.
Public API / Package Surface
cortex/...*
New module cortex.role_manager and RoleManager class added to package surface; CLI exposes new public role command.
Docs/Minor
README.md
Minor formatting tweaks in architecture block (non-functional).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI
    participant RoleManager
    participant FS as File System
    participant AI as AI Inference

    User->>CLI: cortex role detect
    CLI->>RoleManager: get_system_context()
    RoleManager->>FS: probe PATH, read shell histories, check GPUs, read install history DB
    RoleManager-->>CLI: SystemContext
    CLI->>AI: build prompt (nonce, timestamp, patterns)
    AI-->>CLI: recommendations (3-5 roles/packages)
    CLI-->>User: display detected roles & guidance
Loading
sequenceDiagram
    participant User
    participant CLI
    participant RoleManager
    participant FS as File System
    participant AI as AI Inference

    User->>CLI: cortex role set <role_slug>
    CLI->>RoleManager: save_role(role_slug)
    RoleManager->>FS: acquire .env.lock (fcntl/msvcrt)
    RoleManager->>FS: read current .env
    RoleManager->>FS: write .env.tmp
    RoleManager->>FS: rename .env.tmp -> .env (atomic)
    RoleManager->>FS: remove .env.lock
    RoleManager-->>CLI: confirmation
    CLI->>AI: fetch tailored recommendations based on new role
    CLI-->>User: display persisted role and recommendations
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • mikejmorgan-ai
  • Anshgrover23

Poem

🐇 I hop your PATH and sniff each trace,
I hide the bits that show your face,
I count GPUs, learn what you do,
I lock, swap, write — then save for you,
Tiny paws, bright hints — recommendations anew.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description check ✅ Passed The PR description comprehensively covers all required template sections including linked issue, summary, AI disclosure, and a detailed checklist with verification results.
Linked Issues check ✅ Passed The PR successfully implements all primary objectives from issue #119: role detection via RoleManager.get_system_context(), manual role setting via RoleManager.save_role(), AI-driven package recommendations in cli.role commands, learning from installation history, and >80% test coverage (86.63% achieved).
Out of Scope Changes check ✅ Passed All changes directly support role management implementation: RoleManager class for detection/persistence, CLI command wiring, documentation, comprehensive tests, and a minor InstallationType enum extension for audit logging. No extraneous modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 97.22% which is sufficient. The required threshold is 80.00%.
Title check ✅ Passed The title 'feat: system role management and package recommendations' directly and concisely captures the main feature added—a new system role management system with AI-driven package recommendations.

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

✨ Finishing touches
  • 📝 Generate docstrings

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
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: 3

🤖 Fix all issues with AI agents
In @cortex/role_manager.py:
- Around line 45-55: The ML Workstation role detection is too broad because
"python3" in the "binaries" list will match almost any Linux machine; update the
ROLE_ML_WORKSTATION entry so its "binaries" list removes "python3" and instead
uses more specific indicators (e.g., keep "nvidia-smi" and "nvcc" and optionally
add "conda" and "jupyter" or other ML-framework-specific executables) so
detection relies on GPU/tooling presence rather than a generic Python install.

In @docs/ROLES.md:
- Around line 31-34: Remove 'python3' from the ML Workstation detection
signatures and replace it with more specific ML-related binaries (e.g.,
'jupyter', 'conda', maybe 'pip' if desired) in the role detection signatures
array in role_manager.py (the ML workstation signatures/list used to detect that
role), then update the corresponding ML Workstation bullet in ROLES.md to list
those specific tools instead of 'python3' so the docs match the implementation.
🧹 Nitpick comments (4)
tests/test_role_management.py (2)

23-27: Patch target should reference the module under test.

The patch should target cortex.role_manager.shutil.which rather than shutil.which to ensure the mock is applied where the function is looked up. Currently, this works because shutil is imported as a module (not from shutil import which), but the explicit target is more robust.

♻️ Suggested improvement
-    with patch("shutil.which", side_effect=lambda x: "/usr/bin/nginx" if x == "nginx" else None):
+    with patch("cortex.role_manager.shutil.which", side_effect=lambda x: "/usr/bin/nginx" if x == "nginx" else None):

126-142: Test should verify the corrected JSON structure after recovery.

The test validates that learn_package handles malformed JSON, but it should also assert that the resulting file contains valid JSON with the learned package.

♻️ Suggested improvement
     manager = RoleManager(env_path=env_path)
     # The method should catch the error and overwrite/initialize a valid structure
     manager.learn_package("ml-workstation", "numpy")
     assert learned_file.exists()
+
+    # Verify the file now contains valid JSON with the learned package
+    data = json.loads(learned_file.read_text())
+    assert "numpy" in data.get("ml-workstation", [])
cortex/role_manager.py (2)

68-70: Shallow copy of ROLE_DEFINITIONS shares nested dictionaries.

dict.copy() creates a shallow copy, so the nested dictionaries (role configs) are still shared with the class constant. If custom roles modify existing role entries, it could mutate ROLE_DEFINITIONS.

Consider using copy.deepcopy() for full isolation.

♻️ Suggested improvement
+import copy
+
 class RoleManager:
     ...
     def __init__(self, env_path: Path | None = None) -> None:
         ...
-        self.roles = self.ROLE_DEFINITIONS.copy()
+        self.roles = copy.deepcopy(self.ROLE_DEFINITIONS)

12-12: Remove unused Optional import.

The code uses the | None union syntax (Python 3.10+) throughout, so the Optional import from typing is unused.

♻️ Suggested fix
-from typing import Any, Optional
+from typing import Any
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 403f498 and 7b48dfe.

📒 Files selected for processing (5)
  • README.md
  • cortex/cli.py
  • cortex/role_manager.py
  • docs/ROLES.md
  • tests/test_role_management.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_role_management.py
  • cortex/cli.py
  • cortex/role_manager.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Maintain >80% test coverage for pull requests

Files:

  • tests/test_role_management.py
🧬 Code graph analysis (1)
tests/test_role_management.py (1)
cortex/role_manager.py (6)
  • detect_active_roles (91-107)
  • save_role (109-132)
  • get_saved_role (134-150)
  • get_all_slugs (167-174)
  • get_recommendations_by_slug (152-165)
  • learn_package (176-213)
⏰ 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: Test (Python 3.11)
  • GitHub Check: test (3.10)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
🔇 Additional comments (9)
docs/ROLES.md (1)

1-113: Documentation is comprehensive and well-structured.

The documentation covers all key aspects: usage, features (detection, recommendations, learning, custom roles), examples, and technical implementation details. The thread-safe persistence explanation aligns with the actual implementation.

README.md (1)

70-70: README updates accurately reflect the new role management feature.

The additions to features table, command reference, and project structure are consistent with the implementation.

Also applies to: 152-152, 226-226

cortex/cli.py (2)

269-323: Role management CLI implementation looks solid.

The implementation properly:

  • Validates role slugs against the allowed list before saving
  • Handles missing subcommands gracefully
  • Catches and reports exceptions from save_role
  • Returns appropriate exit codes

The structure follows the existing patterns in the codebase (e.g., notify, sandbox methods).


1876-1885: Argument parser setup is correct.

The subparser configuration follows the established pattern and provides appropriate help text.

tests/test_role_management.py (2)

10-15: Fixture is well-designed for isolation.

Using tmp_path ensures each test gets a clean, isolated directory. Good practice for file I/O tests.


84-103: Error handling test is comprehensive.

Testing that save_role raises RuntimeError with the expected message when file I/O fails ensures the error contract is maintained.

cortex/role_manager.py (3)

1-57: Well-designed public API with good documentation.

The class structure is clean with:

  • Clear constant definitions for role slugs
  • Comprehensive docstrings on all public methods
  • Proper type hints throughout
  • Good separation between public API and private implementation details

Also applies to: 91-108, 134-174


215-238: File locking implementation is correct for atomic writes.

The pattern of:

  1. Acquiring exclusive lock via fcntl.flock
  2. Reading existing content
  3. Modifying via callback
  4. Writing to temp file with restrictive permissions (0o600)
  5. Atomically replacing via Path.replace()
  6. Releasing lock in finally

This is a solid approach for process-safe configuration updates.


6-6: This review comment is not applicable to this codebase. Cortex is explicitly designed as "an AI layer for Linux Debian/Ubuntu" and has no stated Windows support requirements. The fcntl module is appropriate for this Linux-only project, and no platform check or fallback mechanism is needed.

Likely an incorrect or invalid review comment.

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: 0

🧹 Nitpick comments (2)
docs/ROLES.md (1)

95-107: Technical implementation snippet is incomplete/illustrative.

The code snippet references temp_file and self.env_file without showing where they're defined, and the modifier function signature isn't shown. While this is acceptable for high-level documentation, consider either:

  • Adding a comment like # Simplified illustration at the top, or
  • Linking to the actual implementation with See role_manager.py:_locked_read_modify_write for full details
cortex/role_manager.py (1)

214-216: The target_file parameter successfully addresses previous concurrency concerns.

The addition of the target_file parameter eliminates the fragile pattern of temporarily swapping self.env_file. This is now properly isolated and thread-safe.

However, the modifier_func: Any type hint could be more precise for better type safety.

♻️ Strengthen type hint for modifier_func
+from typing import Callable
+
 def _locked_read_modify_write(
-    self, key: str, value: str, modifier_func: Any, target_file: Path | None = None
+    self, key: str, value: str, modifier_func: Callable[[str, str, str], str], target_file: Path | None = None
 ) -> None:
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7b48dfe and 16757e1.

📒 Files selected for processing (3)
  • cortex/role_manager.py
  • docs/ROLES.md
  • tests/test_role_management.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_role_management.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.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:

  • cortex/role_manager.py
⏰ 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). (3)
  • GitHub Check: Build Package
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.10)
🔇 Additional comments (2)
cortex/role_manager.py (1)

59-59: No action needed. The project explicitly requires Python 3.10+ (requires-python = ">=3.10" in pyproject.toml), making PEP 604 union syntax (Path | None, str | None) the correct and recommended approach for this codebase.

Likely an incorrect or invalid review comment.

docs/ROLES.md (1)

55-63: The custom role JSON schema in the documentation is correct as written. The "Frontend-Dev" key follows the expected pattern where role dictionary keys are human-readable names (matching the structure of built-in roles like "Web Server", "Database Server"). The slug field within each role object is distinct from the key and serves as the machine-readable identifier. The implementation in role_manager.py (lines 86-88) confirms this by merging custom_data directly via self.roles.update(custom_data), and the test case test_custom_role_loading (lines 46-62) validates that custom roles use human-readable names as keys (e.g., "DevOps"). No changes needed.

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: 1

🤖 Fix all issues with AI agents
In @cortex/role_manager.py:
- Around line 1-16: Remove the unused top-level import of the os module in
role_manager.py: delete the "import os" statement (the symbol os) from the
imports block and ensure no other code references it; after removal, run
linter/tests to verify there are no unused-import warnings or accidental
dependencies on os.
🧹 Nitpick comments (4)
cortex/role_manager.py (4)

74-91: Move json import to module level.

Importing json inside the function (line 83) is inefficient and non-idiomatic. Python best practice is to place all imports at the module level unless there's a specific reason for lazy loading (like avoiding circular imports or heavy optional dependencies). The same issue appears in the learn_package method at line 189.

♻️ Proposed fix

At the module level (after line 6):

 import copy
 import fcntl
+import json
 import logging

Then remove the local imports:

     if not self.custom_roles_file.exists():
         return
 
-    import json
-
     try:

111-134: Consider validating role_slug before persisting.

The method persists role_slug without checking if it's a valid slug from get_all_slugs(). While the CLI may validate this upstream, adding validation here would make RoleManager more robust when used programmatically or in future integrations.

🛡️ Suggested validation
     def save_role(self, role_slug: str) -> None:
         """
         Persists the selected role to the Cortex environment file securely.
 
         Args:
             role_slug: The machine-readable identifier to save.
+
+        Raises:
+            ValueError: If role_slug is not a valid role identifier.
+            RuntimeError: If the role cannot be persisted to disk.
         """
+        if role_slug not in self.get_all_slugs():
+            raise ValueError(f"Invalid role slug: {role_slug}. Valid slugs: {self.get_all_slugs()}")
 
         def modifier(existing_content: str, key: str, value: str) -> str:

154-167: LGTM! Linear search is fine for current scale.

The linear search is acceptable given the small number of roles. If the number of roles grows significantly, consider building a reverse lookup dictionary (slug -> config) for O(1) access.


178-213: Apply the same json import fix here.

Line 189 imports json inside the modifier function. This should be moved to the module level as suggested in the earlier comment for _load_custom_roles.

Otherwise, the thread-safe implementation using target_file properly addresses the past review concern.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 16757e1 and 555ed61.

📒 Files selected for processing (2)
  • cortex/role_manager.py
  • docs/ROLES.md
🧰 Additional context used
📓 Path-based instructions (1)
**/*.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:

  • cortex/role_manager.py
⏰ 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: Test (Python 3.11)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.10)
  • GitHub Check: test (3.12)
🔇 Additional comments (13)
cortex/role_manager.py (6)

19-58: LGTM! Well-structured role definitions.

The class constants and ROLE_DEFINITIONS dictionary are well-organized. The fix to use more specific ML binaries (conda, jupyter) instead of the generic python3 addresses the previous concern effectively.


60-72: LGTM! Solid initialization with defensive copying.

The deep copy of ROLE_DEFINITIONS prevents accidental mutation of the class constant, and the automatic loading of custom roles is a nice touch. The type hints follow modern Python conventions.


93-109: LGTM! Efficient role detection.

The use of any() with shutil.which() is efficient and idiomatic. The per-role exception handling allows partial detection success, which is appropriate for this use case.


136-152: LGTM! Appropriate error handling.

The method correctly returns None when the file doesn't exist or can't be read, which is appropriate for an optional configuration value.


169-176: LGTM! Clean and efficient.

Straightforward list comprehension that clearly expresses intent.


215-255: LGTM! Robust thread-safe implementation.

The implementation correctly uses:

  • Advisory locking with fcntl.flock for process-safe access
  • Atomic writes via temp file and replace() to prevent corruption
  • Restrictive file permissions (0o600) for security
  • Guaranteed lock release in the finally block

This properly addresses the past review concern about temporary file swapping.

docs/ROLES.md (7)

1-23: LGTM! Clear introduction and usage examples.

The documentation provides a clear overview and practical command examples that align with the CLI implementation.


25-42: LGTM! Detection criteria match implementation.

The ML Workstation detection binaries now correctly list specific ML tools (nvidia-smi, nvcc, jupyter, conda) rather than the generic python3, matching the fix in role_manager.py.


44-50: LGTM! Accurate description of learning behavior.

The documentation correctly describes how Cortex learns from installation patterns and stores them in learned_roles.json.


52-63: LGTM! Clear custom role example.

The JSON example is valid and demonstrates the expected structure. The example shows a "Frontend-Dev" role with slug "frontend", which appropriately illustrates the distinction between display name and machine-readable identifier.


65-87: LGTM! Helpful examples with expected output.

The examples clearly demonstrate both detection and role-setting workflows with realistic output that matches the implementation.


89-105: LGTM! Good technical documentation.

The section accurately describes the thread-safe implementation and provides a helpful code snippet illustrating the locking mechanism. The reference to the actual implementation helps developers locate the full code.


107-111: LGTM! Useful cross-references.

The related commands section helps users discover complementary features and understand how role management fits into the broader Cortex ecosystem.

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: 0

🧹 Nitpick comments (2)
cortex/role_manager.py (2)

83-89: Consider more specific exception handling.

The broad Exception catch could mask specific errors like PermissionError or JSONDecodeError. While logging provides visibility, catching more specific exceptions would make debugging easier and allow for different handling strategies.

♻️ Proposed refactor
         try:
             # Atomic read of user-defined roles
             custom_data = json.loads(self.custom_roles_file.read_text())
             # Merge custom roles into the active roles dictionary
             self.roles.update(custom_data)
-        except Exception as e:
-            logger.error(f"Failed to load custom roles from {self.custom_roles_file}: {e}")
+        except json.JSONDecodeError as e:
+            logger.error(f"Invalid JSON in {self.custom_roles_file}: {e}")
+        except (OSError, PermissionError) as e:
+            logger.error(f"Cannot read {self.custom_roles_file}: {e}")

123-125: Minor formatting improvement.

The error message string can be simplified for better readability.

♻️ Proposed refactor
         if role_slug not in self.get_all_slugs():
-            raise ValueError(
-                f"Invalid role slug: {role_slug}. " f"Valid slugs: {self.get_all_slugs()}"
-            )
+            raise ValueError(
+                f"Invalid role slug: {role_slug}. Valid slugs: {self.get_all_slugs()}"
+            )
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 555ed61 and e739756.

📒 Files selected for processing (1)
  • cortex/role_manager.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.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:

  • cortex/role_manager.py
⏰ 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). (3)
  • GitHub Check: Build Package
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.12)
🔇 Additional comments (9)
cortex/role_manager.py (9)

1-16: LGTM! Module imports and docstring are well-organized.

The imports are clean and the module docstring clearly describes the purpose. The previously flagged unused os import has been removed.


19-58: LGTM! Role definitions are well-structured.

The ROLE_DEFINITIONS are clear and the ML Workstation detection now uses specific indicators (nvidia-smi, nvcc, conda, jupyter) instead of the generic python3 binary. This addresses the previous concern about overly broad detection.


60-72: LGTM! Initialization is defensive and well-documented.

Using copy.deepcopy to avoid mutating the class constant is a good defensive practice, and the initialization logic is clear.


91-107: LGTM! Role detection is resilient and efficient.

The use of shutil.which for binary detection is appropriate, and the per-role exception handling ensures that one misconfigured role doesn't break detection for others.


127-142: LGTM! Role persistence logic is robust.

The modifier function correctly handles both updating existing keys and appending new ones, with appropriate edge case handling for trailing newlines.


144-160: LGTM! Role retrieval is defensive with appropriate fallbacks.

The method correctly handles missing files and parse errors by returning None, which is a reasonable default for optional configuration.


162-184: LGTM! Recommendation and slug retrieval methods are straightforward.

Both get_recommendations_by_slug and get_all_slugs have clear logic and appropriate return types.


186-219: LGTM! Package learning implementation is thread-safe and robust.

The use of the target_file parameter addresses the previous concern about temporarily swapping self.env_file. The modifier function correctly handles malformed JSON and prevents duplicate entries.


221-261: LGTM! File locking implementation is secure and atomic.

The implementation correctly uses fcntl for process-safe locking, atomic writes via temporary file, and restrictive file permissions (0o600). The lock is properly released in the finally block.

@Kesavaraja67
Copy link
Contributor Author

Kesavaraja67 commented Jan 7, 2026

@Anshgrover23 can i get a review on this PR please ?

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: 0

🧹 Nitpick comments (3)
cortex/role_manager.py (3)

74-91: Consider validating custom role structure before merging.

Custom roles are merged without validating that they contain required keys (slug, binaries, recommendations). Malformed entries will cause KeyError exceptions later in detect_active_roles or get_recommendations_by_slug.

♻️ Proposed validation
             custom_data = json.loads(self.custom_roles_file.read_text())
-            # Merge custom roles into the active roles dictionary
-            self.roles.update(custom_data)
+            # Validate and merge custom roles into the active roles dictionary
+            required_keys = {"slug", "binaries", "recommendations"}
+            for role_name, config in custom_data.items():
+                if not isinstance(config, dict) or not required_keys.issubset(config.keys()):
+                    logger.warning(f"Skipping invalid custom role '{role_name}': missing required keys")
+                    continue
+                self.roles[role_name] = config

138-142: Chain the original exception for better debugging.

The RuntimeError loses the original exception context. Use from e to preserve the traceback for easier debugging.

♻️ Proposed fix
         except Exception as e:
             logger.error(f"Failed to save system role: {e}")
-            raise RuntimeError(f"Could not persist role to {self.env_file}")
+            raise RuntimeError(f"Could not persist role to {self.env_file}") from e

186-219: Learning mechanism is well-implemented.

Good use of the target_file parameter for thread-safe writes to learned_roles.json. Silent failure is appropriate for this non-critical feature.

One edge case: if learned_roles.json is manually edited and data[key] becomes a non-list type, lines 207-208 would fail. Consider a defensive check if you want extra robustness.

♻️ Optional defensive check
             if key not in data:
                 data[key] = []
+            elif not isinstance(data[key], list):
+                data[key] = []  # Reset corrupted entry

             # Only add the package if it's not already recorded
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e739756 and 8bb6d80.

📒 Files selected for processing (1)
  • cortex/role_manager.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.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:

  • cortex/role_manager.py
⏰ 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.11)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.10)
🔇 Additional comments (8)
cortex/role_manager.py (8)

1-17: Imports and module setup look good.

All imports are used, and the module docstring clearly describes the purpose. Note that fcntl is Unix-only, which limits Windows compatibility—acceptable if Cortex targets Linux systems only.


19-58: Class structure and role definitions are well-designed.

Good use of class-level constants to prevent string typos. The ROLE_DEFINITIONS dictionary is well-typed and the detection binaries are appropriately specific for each role.


60-72: Initialization is correctly implemented.

Good use of copy.deepcopy to avoid mutating the class-level ROLE_DEFINITIONS. Type hints and docstring are properly provided.


93-109: Detection logic is correctly implemented.

Using shutil.which() with any() short-circuit evaluation is efficient and cross-platform. The broad exception handler ensures one malformed role config doesn't break detection of others.


144-160: LGTM!

Safe error handling with fallback to None, and correct regex pattern for parsing the .env format.


162-175: LGTM!

The linear search is appropriate given the small number of roles, and returning an empty list is a safe fallback.


177-184: LGTM!

Simple helper method correctly implemented.


221-261: Thread-safe file operations are correctly implemented.

Excellent implementation of the atomic write pattern with proper advisory locking. Key strengths:

  • Uses target_file parameter to avoid mutating instance state (addressing past review).
  • Exclusive lock with proper release in finally block.
  • Atomic swap via temp_file.replace(target).
  • Secure permissions with chmod(0o600).

@Anshgrover23 Anshgrover23 self-assigned this Jan 8, 2026
@github-actions
Copy link

github-actions bot commented Jan 8, 2026

CLA Verification Passed

All contributors have signed the CLA.

Contributor Signed As
@Kesavaraja67 @Kesavaraja67

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: 0

🧹 Nitpick comments (1)
cortex/role_manager.py (1)

211-220: Remove dead code.

Lines 215-216 are unreachable. The condition if key not in data is already handled by the first check on line 212 (if key not in data or not isinstance(data[key], list)), so this second block will never execute.

♻️ Proposed fix
             # Ensure the entry is a list, even if the file was manually corrupted or edited
             if key not in data or not isinstance(data[key], list):
                 data[key] = []
 
-            if key not in data:
-                data[key] = []
-
             # Only add the package if it's not already recorded
             if value not in data[key]:
                 data[key].append(value)
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8bb6d80 and 180fc11.

📒 Files selected for processing (2)
  • cortex/cli.py
  • cortex/role_manager.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.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:

  • cortex/role_manager.py
  • cortex/cli.py
🧬 Code graph analysis (1)
cortex/cli.py (1)
cortex/role_manager.py (5)
  • RoleManager (19-273)
  • detect_active_roles (100-116)
  • get_all_slugs (185-192)
  • save_role (118-150)
  • get_recommendations_by_slug (170-183)
⏰ 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). (3)
  • GitHub Check: Build Package
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.10)
🔇 Additional comments (14)
cortex/cli.py (4)

26-26: LGTM!

Import is correctly placed and follows the existing pattern.


273-327: Well-structured command handler.

The role method follows established CLI patterns with proper type hints, docstring, graceful error handling, and validation. The dual validation (CLI-level on lines 305-308 and RoleManager-level in save_role) provides defense in depth.


2265-2274: LGTM!

CLI parser additions follow established patterns and provide clear help text for both subcommands.


2589-2590: LGTM!

Command routing is correctly integrated with the existing structure.

cortex/role_manager.py (10)

1-17: LGTM with platform consideration.

Module is well-organized with a clear docstring. Note that fcntl is Unix-only, which aligns with Cortex's Linux focus but will prevent Windows usage.


19-58: LGTM!

Class structure is clean with well-documented constants. Using typed class constants for role slugs prevents typos and enables IDE autocomplete.


60-72: LGTM!

Good defensive programming with copy.deepcopy to prevent mutation of the class constant. Type hints and docstring are complete.


74-98: LGTM!

Robust custom role loading with proper validation and graceful error handling. Invalid roles are skipped with warnings rather than failing the entire load.


100-116: LGTM!

Detection logic is robust with per-role error handling. Using shutil.which is the correct portable approach for checking binary availability.


118-150: LGTM!

Well-designed save logic with input validation, atomic updates, and proper exception chaining for debugging context. The modifier function correctly handles both existing key updates and new key appends.


152-168: LGTM!

Defensive implementation that gracefully returns None on errors rather than crashing.


170-183: LGTM!

Returns empty list for unknown slugs, which is a safer API design than returning None.


185-192: LGTM!

Simple and correct implementation.


233-273: LGTM!

Solid thread-safe and process-safe file update implementation. The pattern of atomic write via temp file + replace() prevents corruption, and the try/finally ensures the lock is always released.

Copy link
Collaborator

@Anshgrover23 Anshgrover23 left a comment

Choose a reason for hiding this comment

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

@Kesavaraja67 Added a comment.

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

🤖 Fix all issues with AI agents
In @cortex/role_manager.py:
- Around line 145-154: The modifier function uses a plain substring check (if
f"{key}=" in existing_content) which can false-positive when the key appears
inside another value; instead use regex detection consistently: compute pattern
= rf"^{key}=.*$" and use re.search(pattern, existing_content,
flags=re.MULTILINE) to decide whether to call re.sub or append; update the
modifier function (symbol: modifier) to replace the substring check with
re.search, leaving the existing re.sub call and the append logic intact.

In @README.md:
- Line 152: Update the README entry for the "cortex role detect" command to
clarify it only analyzes and displays AI recommendations and does not persist
changes; explicitly state that only "cortex role set" persists a role (via
manager.save_role()), and adjust the table cell text to remove "and set system
role" so it accurately reflects the behavior implemented in the detect handler
(which only shows recommendations).
🧹 Nitpick comments (3)
cortex/role_manager.py (2)

36-72: LGTM with a minor suggestion! Robust error handling for shell history.

The defensive error handling and errors="ignore" encoding strategy are appropriate for handling potentially corrupted history files. The early return on first match is intentional and works correctly.

Optional refinement: Consider documenting shell priority order

Since the method returns on the first existing history file, .bash_history takes precedence over .zsh_history. Consider adding a note in the docstring if this priority is intentional:

     """
     Senses user activity patterns from local shell history files.
+    
+    Priority order: .bash_history, then .zsh_history (returns on first match).

182-219: LGTM! Solid atomic write implementation with advisory locking.

The file locking and atomic swap pattern correctly prevents data corruption from concurrent writes. The 0o600 permissions appropriately restrict access to the user only.

Consider documenting advisory locking limitation

The fcntl advisory locking only works if all processes cooperate. Consider adding a note in the docstring:

"""
Standardized utility for atomic, thread-safe file updates.

Implements an advisory locking mechanism using fcntl and an
atomic swap pattern. Note: Advisory locks only prevent concurrent
modifications from processes that also use fcntl locking.
"""

This is informational only - the implementation is correct for Cortex's use case.

tests/test_role_management.py (1)

1-153: LGTM! Comprehensive test coverage for the new feature.

The test suite covers critical scenarios including:

  • Happy path context gathering
  • Error handling and graceful degradation
  • File persistence and updates
  • Edge cases (missing files, no history, idempotency)

The tests are well-structured with clear docstrings and appropriate mocking. The claimed 82.79% coverage is well-supported by these tests.

Optional: Consider testing key collision edge case

Related to my comment on cortex/role_manager.py lines 145-154, you might add a test for the edge case where a key name appears in another variable's value:

def test_save_role_key_in_value_edge_case(temp_cortex_dir):
    """Ensure key detection doesn't match key names within other values."""
    env_path = temp_cortex_dir / ".env"
    env_path.write_text("OTHER_KEY=contains_CORTEX_SYSTEM_ROLE_text\n")
    
    manager = RoleManager(env_path=env_path)
    manager.save_role("web-server")
    
    content = env_path.read_text()
    # Should have exactly one CORTEX_SYSTEM_ROLE at line start
    assert content.count("CORTEX_SYSTEM_ROLE=") == 1
    assert "CORTEX_SYSTEM_ROLE=web-server" in content
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 180fc11 and cc72a45.

📒 Files selected for processing (6)
  • .github/workflows/pr-title-check.yml
  • README.md
  • cortex/cli.py
  • cortex/role_manager.py
  • docs/ROLES.md
  • tests/test_role_management.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/ROLES.md
🧰 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:

  • cortex/cli.py
  • tests/test_role_management.py
  • cortex/role_manager.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Maintain >80% test coverage for pull requests

Files:

  • tests/test_role_management.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 **/*sandbox*.py : Implement Firejail sandboxing for package operations

Applied to files:

  • README.md
🧬 Code graph analysis (2)
cortex/cli.py (1)
cortex/role_manager.py (3)
  • RoleManager (12-219)
  • get_system_context (74-128)
  • save_role (130-161)
tests/test_role_management.py (1)
cortex/role_manager.py (4)
  • get_system_context (74-128)
  • _get_shell_patterns (36-72)
  • save_role (130-161)
  • get_saved_role (163-180)
⏰ 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: Test (Python 3.11)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.10)
🔇 Additional comments (23)
.github/workflows/pr-title-check.yml (1)

7-9: LGTM! Good security practice.

Explicitly limiting permissions to pull-requests: read follows the principle of least privilege for the pull_request_target trigger. This is the correct approach for workflows that only need to read PR metadata.

README.md (4)

70-70: LGTM! Feature description is clear and accurate.

The description "Autonomous role detection and contextual package suggestions" accurately reflects the capabilities of the new RoleManager module.


208-211: LGTM! Architecture diagram update is clear.

The addition of the "AI Role Sensing (Context Layer)" box appropriately represents the new RoleManager component in the system architecture.


227-227: LGTM! Project structure accurately reflects the new module.

The addition of role_manager.py to the project structure is accurate and appropriately documented.


346-346: LGTM! Checklist item appropriately marks feature completion.

The completed checklist item accurately reflects the implementation of the role management feature.

cortex/role_manager.py (4)

1-24: LGTM! Clean imports and well-documented class structure.

The imports are minimal and appropriate, type hints follow modern Python conventions (| union syntax), and the class docstring clearly explains the "sensing layer" purpose.


26-34: LGTM! Constructor design supports testability.

The optional env_path parameter enables dependency injection for testing while providing a sensible default for production use.


74-128: LGTM! Comprehensive context gathering with clear design rationale.

The "Persona Pollution" comment is valuable for understanding the design choice to use active_role instead of role_history. The fallback to "undefined" when no role is saved is appropriate.


163-180: LGTM! Robust read logic with appropriate error handling.

The method gracefully handles missing files and read errors by returning None, which aligns with the "undefined" role fallback in get_system_context.

cortex/cli.py (5)

26-26: LGTM! Import follows existing patterns.

The RoleManager import is clean and consistent with other module imports in the file.


293-327: LGTM! detect action correctly shows recommendations without persisting.

The implementation appropriately separates detection (analysis and display) from persistence. This aligns with the expected behavior where detect is exploratory and set is definitive.

Note: There's a minor documentation inconsistency in README.md line 152 that suggests detect also sets the role, but the implementation correctly only displays recommendations.


2316-2336: LGTM! CLI integration follows established patterns.

The argument parser setup for the role command is consistent with other subcommand structures in the CLI, with clear help text and appropriate required arguments.


2650-2651: LGTM! Command routing is straightforward.

The routing for the role command follows the same pattern as other commands and correctly delegates to cli.role(args).


329-379: LGTM! Solid implementation with error handling and pragmatic optimizations.

The cache-busting timestamp (line 347) and structured prompt format (lines 351-362) function as designed. The timestamp embeds a unique identifier into the prompt itself, which changes the semantic cache key (f"ask:{question}") on each call, ensuring fresh AI recommendations for each role change. The structured example format is a legitimate prompt engineering optimization for smaller models. No evidence found that these model-specific approaches degrade the user experience.

tests/test_role_management.py (9)

1-16: LGTM! Test setup provides proper isolation.

The temp_cortex_dir fixture correctly uses pytest's tmp_path to create isolated test environments, preventing pollution of the user's home directory.


18-46: LGTM! Comprehensive test of context gathering.

The test effectively validates all components of the system context dict (binaries, has_gpu, patterns, active_role) with appropriate mocking of external dependencies.


48-64: LGTM! Validates graceful error handling.

The test confirms that _get_shell_patterns doesn't crash when history files are inaccessible, which is important for robustness across different Linux environments.


66-84: LGTM! Validates atomic role updates.

The test confirms that updating an existing role replaces the value rather than appending, which is critical for maintaining .env file integrity.


86-97: LGTM! Validates preservation of existing env variables.

This test ensures that the role management doesn't interfere with other environment variables, which is essential for a production-ready .env file manager.


99-115: LGTM! Comprehensive error handling validation.

The test verifies both the error message clarity and proper exception chaining, which aids debugging when file operations fail.


117-123: LGTM! Validates missing file handling.

The test confirms that get_saved_role gracefully returns None for missing files, which is the expected behavior for first-time users.


125-135: LGTM! Validates idempotent save operations.

The test confirms that repeatedly saving the same role doesn't create duplicate entries, which is important for file integrity and prevents bloat.


137-153: LGTM! Validates behavior for minimal environments.

The test confirms that the system gracefully handles first-time users or minimal installations where no history or binaries are detected.

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

🤖 Fix all issues with AI agents
In @cortex/role_manager.py:
- Around line 130-162: The save_role flow allows unsanitized role_slug into the
.env via modifier and re.sub which enables newline or '=' injection and
misinterprets backslashes; validate/sanitize the role_slug at the start of
save_role (e.g., reject or canonicalize any value containing newline, '\r' or
'=' and trim/whitelist characters) and raise a clear ValueError before calling
_locked_read_modify_write; in modifier, make the regex safe by using re.escape
on the key when building pattern and use a safe replacement (e.g., supply a
function or escape the replacement) so backslashes in role_slug aren’t treated
as backreferences; keep error handling that raises RuntimeError from the
original exception and reference CONFIG_KEY and env_file as before.
🧹 Nitpick comments (7)
tests/test_role_management.py (4)

10-15: Good fixture; consider typing for readability.
Optional: def temp_cortex_dir(tmp_path: Path) -> Path: to make intent explicit.


18-46: Mocks are a bit too broad; this test can pass for the “wrong” reason.
Patching cortex.role_manager.Path.exists/read_text globally affects both shell history and .env reads inside get_saved_role(), so active_role == "undefined" is currently an artifact of the patched history text not containing the key—not necessarily a true “no saved role” scenario. Consider targeting mocks to just the history paths (e.g., patch Path.home() to tmp_path and create real .bash_history, .zsh_history, .env files), or patch RoleManager.get_saved_role separately to isolate concerns.


99-115: Good assertion of exception chaining; patch scope is very wide.
Patching builtins.open will also affect Path.touch() / Path.write_text() internals, so the failure may occur earlier than the comment implies (not necessarily “file lock”). If you want to specifically test lock acquisition failure, patch fcntl.flock or patch open only when opening the lock file (via a small wrapper/indirection), but current test still validates the CLI-facing contract (RuntimeError with __cause__).


125-135: Idempotency test is good, but doesn’t cover pre-existing duplicates.
If you intend to “self-heal” user-edited .env files with multiple CORTEX_SYSTEM_ROLE lines, add a test for that; otherwise current coverage is fine.

cortex/role_manager.py (3)

74-129: get_system_context() looks coherent; consider avoiding double which("nvidia-smi").
Minor: you already compute detected_binaries; has_gpu could be derived from "nvidia-smi" in detected_binaries to avoid an extra PATH lookup.


163-181: get_saved_role() regex should escape the key and consider common .env variants.
If you keep this generic (takes CONFIG_KEY), prefer re.escape(self.CONFIG_KEY). Optionally support export CORTEX_SYSTEM_ROLE=... if you expect users to edit the file manually.


182-219: Atomic write approach is solid; consider fsync() if durability matters.
If you need crash-durability guarantees (power loss after write, before rename), you’ll want to flush and os.fsync() the temp file (and possibly the directory). If best-effort is fine, current approach is OK.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc72a45 and 154121f.

📒 Files selected for processing (5)
  • README.md
  • cortex/cli.py
  • cortex/role_manager.py
  • docs/ROLES.md
  • tests/test_role_management.py
✅ Files skipped from review due to trivial changes (1)
  • docs/ROLES.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • README.md
  • cortex/cli.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_role_management.py
  • cortex/role_manager.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Maintain >80% test coverage for pull requests

Files:

  • tests/test_role_management.py
🧬 Code graph analysis (1)
tests/test_role_management.py (1)
cortex/role_manager.py (5)
  • RoleManager (12-219)
  • get_system_context (74-128)
  • _get_shell_patterns (36-72)
  • save_role (130-161)
  • get_saved_role (163-180)
⏰ 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.10)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
🔇 Additional comments (6)
tests/test_role_management.py (5)

48-64: Failure-handling coverage is good (PermissionError ⇒ []).
This is a reasonable resilience test for varied environments.


66-84: Nice coverage of “update existing key, don’t duplicate”.
This validates the expected steady-state .env invariant.


86-97: Good guard against clobbering unrelated env vars.


117-123: Good missing-file behavior coverage.


137-153: Good first-run behavior coverage (“undefined” + empty patterns).

cortex/role_manager.py (1)

1-8: No action required. The project explicitly declares Python >=3.10 (requires-python = ">=3.10" in pyproject.toml) and POSIX::Linux support ("Operating System :: POSIX :: Linux" in classifiers). The use of PEP 604 union syntax (Path | None) and the fcntl module are both fully compatible with the declared runtime and platform matrix, which is validated by CI testing against Python 3.10, 3.11, and 3.12 on ubuntu-latest.

Likely an incorrect or invalid review comment.

@Kesavaraja67
Copy link
Contributor Author

@Anshgrover23 i have addressed the change you have mentioned and also fixed the code which was suggested by the coderabbitai. Can you review my PR now...

Copy link
Collaborator

@Anshgrover23 Anshgrover23 left a comment

Choose a reason for hiding this comment

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

@Kesavaraja67 Missing "Learning from installations" feature. Also use Professional English for conversations.

@mikejmorgan-ai mikejmorgan-ai self-assigned this Jan 10, 2026
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

🤖 Fix all issues with AI agents
In @cortex/cli.py:
- Around line 331-340: The code calling manager.save_role(role_slug) in the
"set" branch must catch ValueError from RoleManager and show a user-friendly
message; wrap the save_role call in a try/except ValueError as e, call
self._print_error (or cx_print) with a clear message including str(e) (e.g.,
"Invalid role slug: <msg>") and return a non-zero status (1) so the CLI exits
gracefully; let other exceptions bubble up to the existing generic handler.
- Around line 276-329: The role() method doesn't handle args.role_action being
None and can return None; add an explicit branch to handle a missing subcommand
(check action = getattr(args, "role_action", None) and if action is None) that
prints a brief usage/error (e.g., via console.print or cx_print) and returns a
non-zero int (e.g., return 2) so the CLI always returns an int; place this
branch before the existing if action == "detect": block or as an else: at the
end to ensure role() always returns an int.
🧹 Nitpick comments (2)
cortex/role_manager.py (1)

48-59: Consider refining the export redaction pattern.

The pattern r"(?i)export\s+[^\s]+=[^\s]+" will redact all export commands, including benign ones like export PATH=/usr/bin or export EDITOR=vim. This may hide useful technical context from the AI.

Consider targeting only sensitive-looking exports:

♻️ Proposed refinement
-            r"(?i)export\s+[^\s]+=[^\s]+",  # Catch environment variable exports
+            r"(?i)export\s+(?:[^\s]*(?:key|token|secret|password|passwd|credential|auth)[^\s]*)=[^\s]+",  # Catch sensitive exports
tests/test_role_management.py (1)

173-195: Consider adding edge case tests for slug validation boundaries.

The slug validation regex requires slugs to start and end with alphanumeric characters. Consider adding tests for boundary cases like slugs ending with - or _ (e.g., "dev-") which should be rejected.

💡 Optional test additions
def test_save_role_slug_boundary_validation(temp_cortex_dir):
    """Verify slugs must start and end with alphanumeric chars."""
    env_path = temp_cortex_dir / ".env"
    manager = RoleManager(env_path=env_path)

    # Single character should be valid
    manager.save_role("m")
    assert manager.get_saved_role() == "m"

    # Slugs ending with dash/underscore should be invalid
    with pytest.raises(ValueError):
        manager.save_role("dev-")
    
    with pytest.raises(ValueError):
        manager.save_role("dev_")
    
    # Slugs starting with dash/underscore should be invalid
    with pytest.raises(ValueError):
        manager.save_role("-dev")
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 94d2696 and e84c697.

📒 Files selected for processing (5)
  • README.md
  • cortex/cli.py
  • cortex/role_manager.py
  • docs/ROLES.md
  • tests/test_role_management.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • README.md
  • docs/ROLES.md
🧰 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:

  • cortex/role_manager.py
  • tests/test_role_management.py
  • cortex/cli.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Maintain >80% test coverage for pull requests

Files:

  • tests/test_role_management.py
🧬 Code graph analysis (3)
cortex/role_manager.py (1)
cortex/logging_system.py (2)
  • warning (204-206)
  • debug (196-198)
tests/test_role_management.py (1)
cortex/role_manager.py (4)
  • get_system_context (89-141)
  • _get_shell_patterns (36-87)
  • save_role (143-178)
  • get_saved_role (180-196)
cortex/cli.py (2)
cortex/role_manager.py (3)
  • RoleManager (12-227)
  • get_system_context (89-141)
  • save_role (143-178)
cortex/first_run_wizard.py (1)
  • _print_error (778-780)
⏰ 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 (14)
cortex/cli.py (2)

2304-2323: LGTM!

The role subparser structure is well-defined and follows the established patterns in the codebase. Help text is clear and descriptive.


4-8: LGTM!

The new imports are appropriately added for the cache-busting nonce generation (random, string) and request ID creation (uuid). The RoleManager import enables the new role management functionality.

Also applies to: 29-29

cortex/role_manager.py (5)

12-35: LGTM!

The class is well-documented with a clear docstring explaining its purpose as a "sensing layer" for AI inference. The initialization handles defaults appropriately and uses proper type hints.


89-141: LGTM!

The sensing layer implementation is thorough with good multi-vendor GPU support and a comprehensive list of signature binaries. The method aggregates system facts cleanly for AI inference.


143-178: LGTM!

The slug validation regex correctly handles short slugs (single char), uppercase, dashes, and underscores while preventing injection attacks. The modifier function properly escapes the key and uses a lambda to avoid backreference issues. Exception chaining with from e provides good debuggability.


180-196: LGTM!

The method correctly handles the missing file case and catches exceptions gracefully. The regex pattern safely matches the config key at line start.


198-227: LGTM with minor observation.

The atomic write implementation is solid with proper advisory locking, temp file usage, restricted permissions (0o600), and atomic swap via replace(). The lock file (.lock) is created but never cleaned up, which could accumulate over time, though this is a minor concern for CLI usage.

tests/test_role_management.py (7)

1-15: LGTM!

Clean fixture setup providing proper isolation for file I/O tests. The temp_cortex_dir fixture correctly creates a .cortex subdirectory matching the real structure.


18-46: LGTM!

Good test structure using real files in the temp directory combined with targeted mocks. Validates the key aspects of the sensing layer including binary detection, GPU flag, shell patterns, and default role state.


49-68: LGTM!

Good defensive test verifying that permission errors during history file access don't crash the sensing layer but return an empty list gracefully.


71-138: LGTM!

Excellent coverage of the persistence layer including atomic updates, idempotency, exception chaining, and graceful handling of missing files. The tests properly verify that existing environment variables are preserved.


141-156: LGTM!

Tests the first-time user scenario where no shell history or binaries exist. The broad Path.exists patch is acceptable here since it correctly simulates a clean environment.


159-195: LGTM!

Critical edge case testing that ensures the regex anchoring works correctly (key in value doesn't match) and that the slug validation accepts valid variants while rejecting injection attempts.


198-224: LGTM!

Thorough test for PII redaction verifying that sensitive data (API keys, secrets) are scrubbed while safe technical signals (ls -la) are preserved for AI context.

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: 0

🧹 Nitpick comments (4)
cortex/cli.py (2)

379-379: Unreachable return statement.

Line 379 returns 1 as a safety fallback, but all code paths above already return a value (lines 286, 334, 339, 348, 376). This line is unreachable.

♻️ Remove unreachable code
         console.print("[bold cyan]    cortex install <package_name>[/bold cyan]\n")
         return exit_code
-
-    # Safety fallback to ensure an integer return status.
-    return 1

4-5: Consider documenting cache-busting necessity or reconsidering its use.

The random, string, and uuid imports are used to generate unique identifiers (nonce, timestamp, req_id) in LLM prompts at lines 305–306 and 354 for cache-busting (as noted in the code comments).

While this approach is intentional, it has trade-offs:

  • Adds overhead to every role detection/set operation
  • Makes testing and debugging harder due to non-deterministic prompts
  • Its necessity depends on your LLM provider's caching behavior

If cache-busting is required, add a code comment explaining why your LLM provider necessitates this approach. Otherwise, consider removing these imports and the cache-busting logic.

cortex/role_manager.py (2)

90-142: Consider caching system context for performance.

The get_system_context() method scans for 26 binaries using shutil.which() on every call (line 128). For frequently used commands like cortex role detect, this could add noticeable overhead.

Consider implementing a simple cache with a TTL (e.g., 5 minutes) to avoid rescanning the system on every call:

from functools import lru_cache
import time

@lru_cache(maxsize=1)
def _get_cached_context_with_time(self, cache_time):
    # Implementation here
    ...

def get_system_context(self):
    # Cache for 5 minutes
    cache_time = int(time.time() / 300)
    return self._get_cached_context_with_time(cache_time)

Alternatively, if real-time accuracy is critical, the current implementation is acceptable.


199-228: Solid atomic write implementation with advisory locking.

The _locked_read_modify_write() method implements a correct atomic file update pattern:

  • Creates parent directories safely (line 210)
  • Uses advisory file locking with fcntl (line 216)
  • Writes to temporary file with secure permissions (lines 221-223)
  • Performs atomic rename (line 226)
  • Ensures lock release in finally block (line 228)

One consideration: the lock acquisition at line 216 blocks indefinitely. For a local config file this is likely acceptable, but if you anticipate contention, consider using fcntl.LOCK_EX | fcntl.LOCK_NB with retry logic.

Would you like me to generate an implementation with lock timeout handling?

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e84c697 and a4651b9.

📒 Files selected for processing (3)
  • cortex/cli.py
  • cortex/role_manager.py
  • tests/test_role_management.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:

  • cortex/role_manager.py
  • cortex/cli.py
  • tests/test_role_management.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Maintain >80% test coverage for pull requests

Files:

  • tests/test_role_management.py
⏰ 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). (3)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.10)
  • GitHub Check: test (3.11)
🔇 Additional comments (13)
cortex/cli.py (3)

276-286: LGTM!

The method signature includes proper type hints and has a clear docstring. The guard clause for missing action is appropriate and provides a helpful error message.


2317-2336: LGTM!

The argument parser setup for role commands is well-structured with clear help text and proper argument definitions.


2651-2652: LGTM!

Command routing for the role command follows the established pattern and correctly delegates to the cli.role(args) method.

cortex/role_manager.py (5)

24-34: LGTM!

The __init__ method is well-structured with proper type hints, a clear docstring, and sensible defaults for configuration paths.


36-88: Solid PII redaction implementation.

The shell pattern sensing with PII redaction is well-implemented:

  • Comprehensive regex patterns for sensitive data (API keys, tokens, passwords, headers)
  • Proper error handling with logging
  • UTF-8 encoding with error handling for corrupted data
  • Reasonable limit of 15 recent commands

The redaction logic at lines 77-81 correctly applies multiple patterns and filters out "cortex role set" commands to avoid circular references.


144-179: Well-implemented atomic role persistence.

The save_role() method has several strong qualities:

  • Robust slug validation preventing injection attacks (line 157)
  • Proper exception handling with chaining (line 179)
  • Atomic file updates via _locked_read_modify_write() (line 176)
  • Correct regex escaping to prevent pattern injection (line 163)

The modifier function correctly handles both update and append scenarios with proper newline management.


181-197: LGTM!

The get_saved_role() method correctly handles missing files and parse errors, with appropriate logging and fallback behavior.


1-1: Add platform guard for fcntl import or document Linux-only requirement.

The fcntl module is Unix-specific and will raise ImportError on Windows. While the codebase explicitly targets Linux (documented in cortex/config_manager.py), role_manager.py imports and uses fcntl.flock() (lines 216, 228) without guards. Either wrap the import in a try-except block, add a platform check (consistent with patterns used elsewhere in the codebase like cortex/env_loader.py and cortex/sandbox/sandbox_executor.py), or add clear documentation stating Linux-only support.

tests/test_role_management.py (5)

10-15: LGTM!

The temp_cortex_dir fixture provides proper test isolation by creating a temporary .cortex directory that doesn't pollute the user's home directory.


18-46: Excellent test isolation and coverage.

This test correctly isolates the filesystem using patches and temporary directories while creating real files for realistic testing. The assertions comprehensively verify binary detection, GPU status, pattern extraction, and active role.


49-68: LGTM!

This test correctly verifies that _get_shell_patterns() handles permission errors gracefully by returning an empty list instead of crashing.


71-88: LGTM!

This test verifies the atomic update logic correctly replaces existing role values without creating duplicate entries.


91-245: Comprehensive test suite with excellent coverage.

The remaining tests provide thorough coverage of:

  • Preserving unrelated environment variables (91-101)
  • Error handling with proper exception chaining (104-119)
  • Missing file scenarios (122-126)
  • Idempotent operations (129-138)
  • Edge cases like keys in values (159-170)
  • Slug validation with various formats (173-195, 227-245)
  • PII redaction robustness (198-224)

The test suite achieves >80% coverage as required and follows pytest best practices with clear docstrings, proper fixtures, and focused assertions.

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: 0

🧹 Nitpick comments (1)
cortex/cli.py (1)

336-376: Suggest refining prompt and error formatting.

The set action correctly validates input and handles errors from RoleManager.save_role(). Two refinements:

  1. Line 347: str(e) is redundant in f-strings, which automatically convert exceptions to strings.

  2. Line 364: The prompt instruction "Do NOT repeat previous suggestions" assumes LLM state persistence, but each CLI invocation is stateless. Without conversation history or stored suggestions, this instruction may be ineffective.

♻️ Proposed fix for redundant str() call
-        self._print_error(f"Invalid role slug: {str(e)}")
+        self._print_error(f"Invalid role slug: {e}")
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a4651b9 and 96c4624.

📒 Files selected for processing (1)
  • cortex/cli.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.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:

  • cortex/cli.py
🧬 Code graph analysis (1)
cortex/cli.py (3)
cortex/role_manager.py (3)
  • RoleManager (12-228)
  • get_system_context (90-142)
  • save_role (144-179)
cortex/first_run_wizard.py (1)
  • _print_error (778-780)
cortex/branding.py (1)
  • cx_print (49-69)
⏰ 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: Test (Python 3.10)
  • GitHub Check: test (3.10)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.12)
🔇 Additional comments (5)
cortex/cli.py (5)

4-5: LGTM - Secure and purposeful imports.

The new imports support the role management feature:

  • secrets + string enable cryptographically secure nonce generation
  • uuid provides unique request identifiers
  • RoleManager integration adds the sensing layer

All imports are actively used in the role() method.

Also applies to: 8-8, 29-29


276-286: LGTM - Clean command validation.

The method signature follows PEP 8 with proper type hints and docstring. The subcommand validation pattern is consistent with other CLI handlers in this file (e.g., notify() at line 209, sandbox() at line 505).


288-334: Well-structured role detection with secure nonce generation.

The detect action correctly delegates sensing to RoleManager.get_system_context(), which handles errors internally. The cryptographically secure nonce generation (line 305) using secrets.choice() is best practice for cache-busting identifiers.

The LLM prompt is verbose but appears intentional for guiding the AI response format.


2317-2337: LGTM - Standard argparse configuration.

The role command parser follows the established pattern used throughout the file (e.g., notify at line 2299, sandbox at line 2355). The help text clearly describes each subcommand's purpose.


2651-2652: LGTM - Standard command routing.

The role command routing follows the consistent pattern used for all other commands in the main() function.

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: 1

🤖 Fix all issues with AI agents
In @cortex/role_manager.py:
- Around line 184-200: get_saved_role currently returns an empty string when the
.env contains "CORTEX_SYSTEM_ROLE="; update the method (in get_saved_role) to
normalize whitespace-only/empty matches to None by extracting the captured value
from match.group(1).strip() into a variable and returning that variable if
truthy, otherwise return None; keep the existing regex and error handling so
non-matching or invalid/empty configured roles are treated the same as a missing
file.
🧹 Nitpick comments (5)
cortex/cli.py (2)

307-307: Consider using secrets.token_urlsafe() for cleaner nonce generation.

The current loop-based approach works but is more verbose than necessary. The standard library provides a more idiomatic way to generate random strings.

♻️ Cleaner nonce generation
-            nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(12))
+            nonce = secrets.token_urlsafe(9)[:12]  # Generate 12 URL-safe characters

311-326: Extract hardcoded prompt templates to improve maintainability.

The prompt construction spans 15+ lines with embedded formatting requirements. If prompt engineering evolves or multiple commands need similar prompts, this becomes difficult to maintain.

Consider extracting prompts to a dedicated module (e.g., cortex/prompts.py) or constants at the module level with f-string formatting. This centralizes prompt management and makes A/B testing or prompt versioning easier.

cortex/role_manager.py (3)

27-37: Consider validating env_path for earlier error detection.

The __init__ method accepts an optional env_path but doesn't validate it. If a caller passes an invalid path (e.g., a directory, or a location where the parent directory doesn't exist or isn't writable), the error won't surface until save_role() is called later.

For better error locality, consider validating that the parent directory exists or can be created:

def __init__(self, env_path: Path | None = None) -> None:
    self.env_file = env_path or (Path.home() / ".cortex" / ".env")
    # Validate parent directory
    if not self.env_file.parent.exists():
        logger.warning("Parent directory for env_file does not exist: %s", self.env_file.parent)
    self.history_db = Path.home() / ".cortex" / "history.db"

This is optional since _locked_read_modify_write already does mkdir(parents=True, exist_ok=True) on line 213.


51-63: Consider adding patterns for common cloud provider credentials.

The current redaction patterns are comprehensive, but some common environment variables might slip through:

  • AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY (AWS)
  • GITHUB_TOKEN, GITLAB_TOKEN (Git hosting)
  • GOOGLE_APPLICATION_CREDENTIALS (GCP)

While the generic token pattern on line 54 may catch some of these, adding explicit patterns improves coverage:

sensitive_patterns = [
    # ... existing patterns ...
    r"(?i)AWS_(?:ACCESS_KEY_ID|SECRET_ACCESS_KEY)\s*[:=]\s*[^\s]+",
    r"(?i)(?:GITHUB|GITLAB)_TOKEN\s*[:=]\s*[^\s]+",
    r"(?i)GOOGLE_APPLICATION_CREDENTIALS\s*[:=]\s*[^\s]+",
]

93-145: Consider using TypedDict for better type safety in return value.

The method returns dict[str, Any], which loses type information. The caller (CLI) accesses specific keys like context.get("binaries") and context.get("has_gpu"), but the IDE and type checker can't validate these.

Define a TypedDict for the return type:

from typing import TypedDict

class SystemContext(TypedDict):
    binaries: list[str]
    has_gpu: bool
    patterns: list[str]
    active_role: str
    has_install_history: bool

def get_system_context(self) -> SystemContext:
    # ... existing implementation ...

This improves IDE autocomplete and catches typos at type-checking time.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96c4624 and ff73e6a.

📒 Files selected for processing (2)
  • cortex/cli.py
  • cortex/role_manager.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.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:

  • cortex/cli.py
  • cortex/role_manager.py
🧬 Code graph analysis (1)
cortex/cli.py (2)
cortex/role_manager.py (2)
  • get_system_context (93-145)
  • save_role (147-182)
cortex/first_run_wizard.py (1)
  • _print_error (778-780)
⏰ 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.11)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.10)
🔇 Additional comments (7)
cortex/cli.py (3)

2316-2336: LGTM! Well-structured argument parser for role management.

The subparser setup is clean with descriptive help text. The detect and set subcommands are properly defined, and the required role_slug argument for set ensures correct usage.


2650-2651: LGTM! Proper routing for the role command.

The routing correctly delegates to cli.role(args) when the command is "role".


288-290: No error handling wrapper needed for get_system_context().

The method is already designed with comprehensive internal error handling. The helper methods _get_shell_patterns() and get_saved_role() both catch exceptions and return safe defaults (empty list and None respectively). The base operations (shutil.which(), Path.exists()) do not raise exceptions. Since all failure paths are handled internally, the method cannot raise exceptions and will always return a dict with safe default values.

Likely an incorrect or invalid review comment.

cortex/role_manager.py (4)

1-4: Document that thread-safe locking is unavailable on Windows.

The fcntl guard on lines 1-4 allows the code to run on Windows, but lines 219-220 and 232-233 only apply locking when fcntl is available. On Windows, fcntl is None, so the locking is skipped, which means concurrent writes to the .env file are not protected.

While the PR objectives emphasize "Thread-Safe Persistence" using fcntl advisory locking, this guarantee only holds on POSIX systems. Since the project is "cortexlinux," this may be acceptable, but the limitation should be documented in the class or method docstring.

Consider adding a note to the class docstring or raising an informative warning on non-POSIX systems:

if fcntl is None:
    logger.warning("Thread-safe locking unavailable on this platform")

Also applies to: 219-220, 232-233


147-183: LGTM! Robust validation and atomic persistence.

The role slug validation on line 160 correctly enforces:

  • Alphanumeric start and end
  • Optional middle characters (alphanumeric, dash, underscore)
  • Rejects empty strings, trailing dashes, and malicious input

The modifier function safely updates the config file using regex replacement with proper escaping, and error handling provides clear context when persistence fails.


227-227: Fixed permissions ensure security but don't preserve originals.

Line 227 sets the file permissions to 0o600 (user read/write only), which is a secure default for a .env file containing potentially sensitive configuration. However, this doesn't preserve the original permissions if the user had customized them.

For a .env file, this is likely the correct approach for security, but it's worth noting as intentional behavior.


202-233: LGTM! Solid atomic write implementation with advisory locking.

The implementation correctly:

  • Creates parent directories as needed (line 213)
  • Uses advisory locking for concurrency control (lines 220, 233)
  • Writes to a temporary file before atomic swap (lines 225-230)
  • Ensures cleanup in a finally block (lines 231-233)

The atomic replace() operation on line 230 is POSIX-compliant and ensures data integrity even if the process crashes mid-write.

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: 1

🧹 Nitpick comments (6)
cortex/cli.py (2)

5-5: Unused import: string module is not referenced.

The string module is imported but never used in the code. Consider removing it to keep imports clean.

🧹 Proposed fix
 import argparse
 import logging
 import os
 import secrets
-import string
 import sys
 import time
 import uuid

307-308: Redundant slice in nonce generation.

secrets.token_urlsafe(9) already produces exactly 12 characters (9 bytes encoded as base64), so the [:12] slice is unnecessary. While harmless, it can be simplified.

♻️ Proposed simplification
-            nonce = secrets.token_urlsafe(9)[:12]
+            nonce = secrets.token_urlsafe(9)
cortex/role_manager.py (4)

62-77: Comprehensive PII redaction patterns with room for improvement.

The regex patterns cover major credential types well. However, consider these additions:

  • Private keys: r"(?i)-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----"
  • Database URLs: r"(?i)(?:postgres|mysql|mongodb)://[^@]+@" (captures user:pass in connection strings)
  • SSH passwords: r"(?i)sshpass\s+-p\s+[^\s]+"
♻️ Proposed additional patterns
             r"(?i)AWS_(?:ACCESS_KEY_ID|SECRET_ACCESS_KEY)\s*[:=]\s*[^\s]+",
             r"(?i)(?:GITHUB|GITLAB)_TOKEN\s*[:=]\s*[^\s]+",
             r"(?i)GOOGLE_APPLICATION_CREDENTIALS\s*[:=]\s*[^\s]+",
+            r"(?i)-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----",
+            r"(?i)(?:postgres|mysql|mongodb)://[^@\s]+:[^@\s]+@",
+            r"(?i)sshpass\s+-p\s+[^\s]+",
         ]

94-98: Minor performance consideration: repeated regex matching.

The comprehension at line 95 runs all 16+ regex patterns against each command. For 15 commands, this is ~240 regex operations. While acceptable for this small scale, consider precompiling patterns if this becomes a bottleneck:

compiled_patterns = [re.compile(p) for p in sensitive_patterns]
# Then use: any(p.search(cmd) for p in compiled_patterns)

This is a micro-optimization and not necessary now given the small input size.


209-213: Consider explicit encoding for cross-platform consistency.

Line 210 uses read_text() without specifying encoding, which defaults to the system's locale encoding. On Windows, this could be cp1252 or other non-UTF-8 encodings, potentially causing issues if the role slug contains non-ASCII characters.

♻️ Proposed fix
         try:
-            content = self.env_file.read_text()
+            content = self.env_file.read_text(encoding="utf-8")
             match = re.search(rf"^{self.CONFIG_KEY}=(.*)$", content, re.MULTILINE)

225-226: Expand docstring for critical atomic write operation.

The current docstring is minimal for such a critical operation. Consider adding details about:

  • The atomic write-then-swap pattern
  • Advisory locking behavior (POSIX only)
  • The purpose of the modifier_func parameter
  • Exception handling expectations
📝 Proposed enhanced docstring
def _locked_read_modify_write(
    self,
    key: str,
    value: str,
    modifier_func: Callable[[str, str, str], str],
    target_file: Path | None = None,
) -> None:
    """
    Performs an atomic, thread-safe file update with advisory locking.
    
    Uses a write-to-temp-then-replace pattern to ensure atomicity. On POSIX
    systems, fcntl advisory locks prevent concurrent writes. On Windows,
    locking is unavailable but atomicity is still provided by the OS-level
    file replace operation.
    
    Args:
        key: Configuration key to update
        value: New value for the key
        modifier_func: Function that takes (existing_content, key, value)
                      and returns the modified content
        target_file: Optional override for the target file path
                    (defaults to self.env_file)
    
    Raises:
        OSError: If file operations fail
        Exception: Propagates exceptions from modifier_func
    """
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff73e6a and 07a78d8.

📒 Files selected for processing (2)
  • cortex/cli.py
  • cortex/role_manager.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.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:

  • cortex/cli.py
  • cortex/role_manager.py
🧬 Code graph analysis (1)
cortex/cli.py (2)
cortex/role_manager.py (3)
  • RoleManager (25-249)
  • get_system_context (107-160)
  • save_role (162-197)
cortex/first_run_wizard.py (1)
  • _print_error (778-780)
⏰ 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: Test (Python 3.12)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.10)
🔇 Additional comments (13)
cortex/cli.py (6)

276-286: LGTM! Well-structured subcommand validation.

The method correctly validates the presence of a subcommand and returns early with a clear error message.


288-303: Consider error handling for context retrieval.

The get_system_context() call could potentially raise exceptions (e.g., permission errors when reading shell history). While the RoleManager handles these internally with logging, consider wrapping this in a try-except block to provide user-friendly error messages if the context gathering fails entirely.

As per coding guidelines, the RoleManager methods may raise exceptions that should be caught here for better UX.


311-326: Verify prompt injection safety with shell patterns.

The prompt embeds patterns_str which contains user shell history. While RoleManager redacts sensitive patterns, confirm that the redaction is comprehensive enough to prevent prompt injection or exposure of unintended commands.

Based on learnings, shell history can contain arbitrary user input. Review the redaction patterns in RoleManager._get_shell_patterns() to ensure coverage of edge cases.


338-350: Excellent error handling for role validation.

The try-except block properly catches ValueError from save_role() and provides a user-friendly error message, returning an appropriate exit code.


2316-2336: LGTM! Clear and well-structured command definitions.

The role command parser is properly configured with descriptive help text and appropriate subcommands. The role_slug argument for the "set" subcommand is correctly marked as required.


2650-2651: LGTM! Consistent command routing.

The dispatch logic for the "role" command follows the same pattern as other commands in the CLI.

cortex/role_manager.py (7)

1-4: Advisory locking disabled on Windows - acceptable trade-off.

The graceful fallback for fcntl (unavailable on Windows) means file locking is silently disabled on that platform. Since these are advisory locks for process-safe writes, and Cortex appears to be Linux-focused (per PR objectives), this is an acceptable design choice. Just be aware that concurrent writes on Windows could theoretically corrupt the config file.

Based on learnings, this approach is consistent with Linux-first design philosophy.


15-23: LGTM! Well-structured TypedDict.

The SystemContext TypedDict provides clear type hints and documentation for the system context structure, aligning with the coding guidelines requirement for type hints.


37-47: LGTM! Clean constructor with sensible defaults.

The constructor follows coding guidelines with type hints and docstrings. The default paths are appropriate, and the optional env_path parameter enables testing flexibility.


87-87: Good practice: error-tolerant encoding.

Using errors="ignore" when reading shell history is appropriate since these files may contain binary data or encoding issues.


107-160: Excellent system context aggregation.

The method effectively collects system signals with:

  • Comprehensive binary detection covering multiple domains (web, DB, ML, dev ops)
  • Multi-vendor GPU detection (NVIDIA, AMD, Intel)
  • Clean use of shutil.which() for PATH scanning
  • Appropriate fallback handling for get_saved_role() with or "undefined"

162-197: Robust role persistence with excellent validation.

The method demonstrates best practices:

  • Line 175: Strong regex validation prevents injection attacks and malformed slugs
  • Lines 179-191: The modifier function correctly handles both update and append cases with proper newline handling
  • Line 186: Using a lambda prevents backslash escaping issues in regex substitution
  • Lines 193-197: Proper exception wrapping with context preservation

228-249: Excellent atomic write implementation.

The method demonstrates best practices for safe file updates:

  • Line 229: Creates parent directories as needed
  • Lines 234-236: Uses advisory locking (POSIX) with proper fallback
  • Line 243: Sets restrictive 0o600 permissions on temp file (user-only access)
  • Line 246: Uses Path.replace() for atomic swap (guaranteed by OS)
  • Lines 247-249: Ensures lock release in finally block

The write-to-temp-then-replace pattern prevents corruption if the process crashes mid-write.

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: 1

🤖 Fix all issues with AI agents
In @cortex/role_manager.py:
- Around line 222-270: In _locked_read_modify_write, the file reads/writes use
platform-default encodings; update calls to target.read_text() and
temp_file.write_text() to explicitly pass encoding="utf-8" (e.g., existing =
target.read_text(encoding="utf-8") and temp_file.write_text(updated,
encoding="utf-8")), preserving the rest of the logic (including chmod and
replace) so file operations are consistently UTF-8 encoded.
🧹 Nitpick comments (2)
cortex/role_manager.py (1)

49-107: Consider expanding PII redaction patterns for cloud credentials.

The current redaction patterns are solid and cover common cases (API keys, tokens, passwords, SSH keys, database URLs). However, you could enhance coverage by adding:

  • Azure credentials: (?i)AZURE_(?:CLIENT_SECRET|TENANT_ID|SUBSCRIPTION_ID)
  • GCP service accounts: (?i)\.json.*service_account
  • Docker registry credentials: (?i)docker\s+login.*-p\s+[^\s]+
  • SSH agent forwarding: (?i)ssh-add.*-k

These additions would improve protection against accidental credential exposure in shell history.

🔐 Proposed additional patterns
             r"(?i)-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----",
             r"(?i)(?:postgres|mysql|mongodb)://[^@\s]+:[^@\s]+@",
             r"(?i)sshpass\s+-p\s+[^\s]+",
+            r"(?i)AZURE_(?:CLIENT_SECRET|TENANT_ID|SUBSCRIPTION_ID)\s*[:=]\s*[^\s]+",
+            r"(?i)GCP_(?:SERVICE_ACCOUNT|CREDENTIALS)\s*[:=]\s*[^\s]+",
+            r"(?i)docker\s+login.*-p\s+[^\s]+",
         ]
cortex/cli.py (1)

4-5: Remove unused import.

The string module is imported on line 5 but doesn't appear to be used anywhere in the role management implementation. Removing unused imports keeps the codebase clean and passes linters.

🧹 Proposed cleanup
 import secrets
-import string
 import sys
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 07a78d8 and 35dcfac.

📒 Files selected for processing (2)
  • cortex/cli.py
  • cortex/role_manager.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.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:

  • cortex/role_manager.py
  • cortex/cli.py
⏰ 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.10)
  • GitHub Check: test (3.11)
🔇 Additional comments (11)
cortex/role_manager.py (6)

1-12: LGTM! Clean imports and proper cross-platform handling.

The conditional fcntl import with fallback is the correct pattern for cross-platform compatibility (Windows doesn't have fcntl). Module-level logger initialization follows best practices.


15-22: LGTM! Well-defined typed dictionary.

Clear structure with proper type annotations and documentation. Provides a strong contract for system context data.


25-47: LGTM! Well-documented class with proper initialization.

The class docstring clearly describes its role as a "sensing layer". Type hints and documentation meet requirements. Default path handling is appropriate.


109-162: LGTM! Comprehensive system sensing with multi-vendor support.

The signal detection covers a broad range of use cases (Web, DB, ML, DevOps, Development) and includes multi-vendor GPU detection. The implementation correctly uses shutil.which() for PATH-based detection and returns a properly typed SystemContext dictionary.


164-199: LGTM! Robust role slug validation and atomic persistence.

The validation regex correctly allows professional slug formats (including single characters, mixed case, and separators). The modifier function properly handles both update and append cases with correct newline handling. Good use of lambda to avoid regex replacement gotchas.


201-220: LGTM! Clean read logic with proper normalization.

Explicit UTF-8 encoding ensures consistency. The normalization of whitespace-only values to None (lines 216-217) is a good defensive practice.

cortex/cli.py (5)

276-286: LGTM! Proper method signature and validation.

Type hints and docstring are present as required. Early validation of the subcommand prevents downstream errors.


288-336: LGTM! Well-designed AI prompt with effective cache busting.

The cache-busting strategy using cryptographic randomness (line 307) and microsecond timestamps (line 308) is effective for preventing stale LLM responses. The prompt structure is clear and provides comprehensive context for AI inference.

The prompt design follows good practices:

  • Unique session identifiers prevent caching
  • Structured environmental context
  • Clear, specific task requirements
  • Primed response format

338-378: LGTM! Robust error handling and well-structured recommendations flow.

The error handling properly catches ValueError from role slug validation and provides user-friendly feedback. The unique request ID generation (line 356) effectively prevents cached responses. The advisory prompt clearly instructs the AI to provide fresh, role-specific recommendations.


2316-2336: LGTM! Clean CLI argument structure.

The argument parser setup is well-organized with clear help messages. The detect and set subcommands are properly configured with appropriate arguments.


2650-2651: LGTM! Standard command routing.

The routing follows the established pattern used by other CLI commands.

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: 4

🤖 Fix all issues with AI agents
In @cortex/role_manager.py:
- Around line 117-170: In get_system_context, the list comprehension
detected_binaries = [bin for bin in signals if shutil.which(bin)] shadows the
built-in bin(); rename the loop variable (e.g., signal or s) to avoid masking
bin and potential confusion; update the comprehension to detected_binaries =
[signal for signal in signals if shutil.which(signal)] and ensure any related
references remain consistent (get_system_context, signals, detected_binaries,
shutil.which).
- Around line 209-229: get_saved_role currently assumes UTF-8 and a strict
"CORTEX_SYSTEM_ROLE=VALUE" format; update get_saved_role to read env_file bytes
and decode with errors='replace' (or open with encoding="utf-8",
errors="replace") to avoid decode exceptions, then use a more tolerant regex
anchored per-line that allows optional leading "export", optional spaces around
the key and "=", and optional surrounding single or double quotes around the
value (use self.CONFIG_KEY in the pattern), normalize the captured group by
stripping whitespace and surrounding quotes, and return None when no meaningful
value is found while still logging non-fatal errors via logger.error.
- Around line 49-115: _get_shell_patterns currently reads raw shell history and
returns full commands (even when not matched) and recompiles regexes each call;
add an opt-out and stronger minimization plus precompilation: introduce a
module-level precompiled_sensitive_patterns (precompile all entries from
sensitive_patterns) and replace the inline list with that; add an env/config
flag (e.g., SENSE_SHELL_HISTORY or CORTEX_SENSE_HISTORY) check at the start of
_get_shell_patterns to return [] immediately when disabled; when enabled,
transform non-sensitive commands into coarse-grained intent tokens (map common
verbs like install, start, kubectl/helm, git, docker -> "intent:install",
"intent:k8s", "intent:git", etc.) instead of returning raw commands, and keep
exact "<redacted>" for matched sensitive patterns; preserve the existing
exception handling and keep filtering out "cortex role set".
🧹 Nitpick comments (1)
cortex/role_manager.py (1)

1-4: Make fcntl import/type explicit for type-checkers and readability.

Right now fcntl flips between “module” and None, which can confuse static analysis; consider annotating it (or importing ModuleType) to keep tooling happy.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 35dcfac and 229c141.

📒 Files selected for processing (2)
  • cortex/cli.py
  • cortex/role_manager.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • cortex/cli.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.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:

  • cortex/role_manager.py
🧬 Code graph analysis (1)
cortex/role_manager.py (4)
cortex/transaction_history.py (1)
  • search (429-463)
cortex/logging_system.py (2)
  • warning (204-206)
  • debug (196-198)
cortex/graceful_degradation.py (1)
  • match (280-313)
cortex/kernel_features/llm_device.py (1)
  • open (158-159)
⏰ 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 (1)
cortex/role_manager.py (1)

172-208: Role slug validation + atomic update hook look solid.

The re.fullmatch(...) validation (Line 185-187) prevents newline/= injection into the env file, and the modifier function cleanly updates-or-appends the key.

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: 4

🤖 Fix all issues with AI agents
In @cortex/role_manager.py:
- Around line 257-314: Modify _locked_read_modify_write to avoid lock/temp
filename collisions by using the full target filename when creating companion
files (e.g., create lock_file with target.parent.joinpath(f"{target.name}.lock")
and temp_file with target.parent.joinpath(f"{target.name}.tmp") instead of
with_suffix), and add symmetric error handling around temp_file.chmod(0o600)
(wrap it in a try/except like the lock_file.chmod block) so chmod failures on
some platforms are ignored safely; keep the existing locking, read/modify/write,
replace and cleanup logic intact.

In @tests/test_role_management.py:
- Around line 288-297: The test docstring for
test_get_shell_patterns_corrupted_data claims it verifies errors="replace" but
the code in role_manager._get_shell_patterns reads history files with
errors="ignore"; update either the test docstring to state it verifies
errors="ignore" or change the file-reading call inside _get_shell_patterns to
use errors="replace" to match the docstring; locate the history file read in
_get_shell_patterns and make the corresponding change (or edit the test
docstring) so the comment and implementation are consistent.
🧹 Nitpick comments (6)
tests/test_role_management.py (3)

56-76: Patch scope is a bit broad; consider targeting the instance path read only.
patch.object(Path, "read_text", ...) affects all Path.read_text calls in this test context. It works here, but it’s easy to accidentally expand coverage later and make it flaky.


148-164: Avoid patching cortex.role_manager.Path.exists if you only need “no history”.
This also forces self.history_db.exists() false (maybe intended), and can mask regressions in get_saved_role() behavior if the test expands. Prefer patching Path.home + “no history files exist” on disk.


205-232: Redaction test is valuable; consider asserting per-line redaction.
Right now it only checks substrings don’t appear. Adding an assertion like “both sensitive lines become <redacted>” would make leaks harder to reintroduce.

cortex/role_manager.py (3)

11-25: Conditional imports are fine; consider logging when no locking backend is available.
If fcntl is None and msvcrt is None, updates become non-atomic under concurrency with no signal to the user.


202-229: save_role() updates can unexpectedly drop export / quotes from existing files.
If a user already has export CORTEX_SYSTEM_ROLE="foo", your replace path rewrites it to CORTEX_SYSTEM_ROLE=bar. If you want to preserve formatting, capture and re-emit the prefix/quote style.


230-255: Parsing is “tolerant”, but still misses common cases (leading spaces, duplicates, inline comments).
Suggestions:

  • allow ^\s* before optional export
  • if multiple matches exist, prefer the last (shell semantics)
  • optionally ignore trailing # comment when unquoted
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 229c141 and 9548abe.

📒 Files selected for processing (2)
  • cortex/role_manager.py
  • tests/test_role_management.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:

  • cortex/role_manager.py
  • tests/test_role_management.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Maintain >80% test coverage for pull requests

Files:

  • tests/test_role_management.py
🧬 Code graph analysis (1)
tests/test_role_management.py (1)
cortex/role_manager.py (4)
  • get_system_context (156-200)
  • _get_shell_patterns (87-154)
  • save_role (202-228)
  • get_saved_role (230-255)
⏰ 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). (5)
  • GitHub Check: Test (Python 3.12)
  • GitHub Check: Test (Python 3.10)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.10)
  • GitHub Check: test (3.12)
🔇 Additional comments (6)
tests/test_role_management.py (5)

10-23: Fixtures look clean and properly isolate $HOME/I/O.
Using tmp_path and injecting env_path keeps tests hermetic.


25-54: Good “fact gathering” coverage; mocks are scoped and realistic.
Patching cortex.role_manager.Path.home (module-local) + writing a real history file avoids global Path surprises.


78-109: Role persistence tests are strong (update vs append + idempotency).
These assertions map well to the “single key, no duplication” contract.


111-127: Nice: verifies exception chaining (raise ... from e).
This makes CLI error reporting much easier to debug.


274-286: Windows fallback is exercised, but it doesn’t validate real locking constraints.
Since msvcrt is mocked, this won’t catch issues like “locking a 1-byte range on an empty lock file”. Consider adding an assertion that the lock file is non-empty (or update implementation to ensure it), then assert the locking call args.

cortex/role_manager.py (1)

156-200: get_system_context() looks consistent and easy to test.
Nice touch avoiding built-in shadowing (signal).

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: 5

🤖 Fix all issues with AI agents
In @cortex/role_manager.py:
- Around line 301-387: The Windows locking path in _locked_read_modify_write
uses msvcrt.locking(lock_fd.fileno(), ...) without positioning the file handle,
so the byte-range lock may be applied at an unexpected offset; before calling
msvcrt.locking(...) for both acquire and release, seek the lock_fd to a known
offset (e.g., lock_fd.seek(0)) and optionally truncate/ensure at least one byte
is present so the 1-byte lock refers to a stable region; update references to
lock_fd in the acquire and release branches (msvcrt.locking(..., msvcrt.LK_LOCK,
1) and msvcrt.locking(..., msvcrt.LK_UNLCK, 1)) to perform the seek(0) first so
locking/unlocking target the same byte.

In @tests/test_role_management.py:
- Around line 36-66: The test patches Path.home only after creating the
RoleManager, so any home-derived attributes set in RoleManager.__init__ (e.g.,
history_db) still point to the real home; fix by applying the Path.home patch
before instantiating RoleManager or by explicitly overriding manager.history_db
(and any other home-derived attributes) to point to temp_cortex_dir after
construction; locate RoleManager.__init__, the test function
test_get_system_context_fact_gathering, and references to
manager.history_db/get_system_context to update the test accordingly.
- Around line 156-170: The test's caplog assertion is brittle because it doesn't
set a capture level or logger; before calling role_manager.save_role in
test_locked_write_concurrency_degraded_logging, call
caplog.set_level(logging.WARNING, logger="cortex.role_manager") (and add an
import for the logging module if missing) so the warning from the role_manager
logger is reliably captured; alternatively use caplog.set_level(logging.WARNING)
to capture warnings from the root logger, then assert "No file locking backend
available" in caplog.text.
🧹 Nitpick comments (4)
tests/test_role_management.py (2)

11-34: Good isolation for .env writes; consider also isolating history_db to avoid host leakage.
RoleManager(env_path=...) still derives history_db from the real home dir, so get_system_context()["has_install_history"] can depend on the machine running tests (even if you’re not asserting it today).


249-264: Windows locking test: good intent; consider asserting call args for the locked byte range.
Today it only checks .called. If the implementation ever accidentally locks 0 bytes or unlocks incorrectly, this won’t catch it.

cortex/role_manager.py (2)

77-86: env_path override should probably also relocate history_db.
Right now RoleManager(env_path=some/dir/.env) still uses Path.home()/.cortex/history.db, which is surprising and complicates test isolation.

Proposed refactor
 class RoleManager:
@@
     def __init__(self, env_path: Path | None = None) -> None:
@@
-        self.env_file = env_path or (Path.home() / ".cortex" / ".env")
-        self.history_db = Path.home() / ".cortex" / "history.db"
+        base_dir = (env_path.parent if env_path else (Path.home() / ".cortex"))
+        self.env_file = env_path or (base_dir / ".env")
+        self.history_db = base_dir / "history.db"

87-187: _get_shell_patterns() is generally robust, but Windows path minimization is incomplete.
You only basename-strip when "/" in verb; on Windows you can leak local paths with C:\... (backslashes). Consider normalizing both separators before emitting intent:{verb}.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9548abe and ea2be18.

📒 Files selected for processing (2)
  • cortex/role_manager.py
  • tests/test_role_management.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:

  • cortex/role_manager.py
  • tests/test_role_management.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Maintain >80% test coverage for pull requests

Files:

  • tests/test_role_management.py
🧬 Code graph analysis (2)
cortex/role_manager.py (1)
cortex/logging_system.py (2)
  • warning (204-206)
  • debug (196-198)
tests/test_role_management.py (1)
cortex/role_manager.py (4)
  • get_system_context (188-232)
  • _get_shell_patterns (87-186)
  • save_role (234-266)
  • get_saved_role (268-299)
⏰ 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: Test (Python 3.10)
  • GitHub Check: test (3.10)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
🔇 Additional comments (4)
tests/test_role_management.py (1)

68-97: Nice coverage of privacy hardening behaviors (zsh format, env assignment stripping, path minimization, malformed quoting).
This is the right level of “behavioral contract” testing for _get_shell_patterns().

cortex/role_manager.py (3)

1-25: Conditional fcntl/msvcrt import pattern looks solid and testable.
Keeping these as module globals also makes your monkeypatch-based tests straightforward.


29-37: SystemContext is clear and appropriately minimal.
The fields align with what you actually populate in get_system_context().


268-300: get_saved_role() parsing is tolerant and matches the tests well.
Picking the last match is the right call for typical shell override semantics.

@Anshgrover23
Copy link
Collaborator

Anshgrover23 commented Jan 13, 2026

Can you review my PR...

@Kesavaraja67 Please correct the English and ensure the comments are written in a clear, professional manner, in line with our contribution guidelines.
The PR will be reopened after this is addressed.

@Kesavaraja67
Copy link
Contributor Author

@Anshgrover23, I’ve cleaned up the documentation and comments to meet the contribution guidelines. Everything is now written in a more formal, professional tone.

@Anshgrover23 Anshgrover23 reopened this Jan 13, 2026
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: 0

🧹 Nitpick comments (1)
tests/test_role_management.py (1)

409-426: Clarify test intent: This tests defensive cleanup, not a real failure path.

The breaking_modifier manually creates the temp file (line 419-420), but in the actual _locked_read_modify_write implementation, temp_file.write_text() is called after modifier_func() (line 414 in role_manager.py). So the temp file wouldn't exist if the modifier crashes.

This test validates that the finally block defensively cleans up orphaned temp files, which is valuable for scenarios like crashes during temp_file.write_text() or temp_file.replace(). Consider updating the docstring to clarify this tests defensive cleanup rather than a specific failure mode.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b8228b7 and f723f71.

📒 Files selected for processing (2)
  • cortex/role_manager.py
  • tests/test_role_management.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Follow PEP 8 style guide for Python code
Include type hints in Python code
Add docstrings for all public APIs in Python code
Use dry-run mode by default for all installation operations
Do not use silent sudo - require explicit user confirmation for privilege escalation
Implement Firejail sandboxing for execution of untrusted code
Log all operations to ~/.cortex/history.db for audit purposes

Files:

  • cortex/role_manager.py
  • tests/test_role_management.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Maintain test coverage above 80% for pull requests

Files:

  • tests/test_role_management.py
🧠 Learnings (1)
📚 Learning: 2026-01-12T20:51:13.817Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T20:51:13.817Z
Learning: Applies to **/*.py : Log all operations to ~/.cortex/history.db for audit purposes

Applied to files:

  • cortex/role_manager.py
🧬 Code graph analysis (2)
cortex/role_manager.py (1)
cortex/context_memory.py (1)
  • Pattern (46-56)
tests/test_role_management.py (1)
cortex/role_manager.py (5)
  • get_system_context (193-249)
  • _get_shell_patterns (98-191)
  • save_role (251-332)
  • get_saved_role (334-360)
  • _locked_read_modify_write (362-432)
⏰ 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). (7)
  • GitHub Check: Build Package
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.10)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.10)
  • GitHub Check: test (3.12)
🔇 Additional comments (17)
tests/test_role_management.py (7)

17-54: Well-designed hermetic test fixtures.

The temp_cortex_dir and role_manager fixtures provide excellent test isolation, ensuring tests don't interact with the actual user configuration. The use of env_path.parent to derive base_dir and home_path is a clean approach for redirecting all derived paths (history.db, shell history) to the temporary directory.


57-107: Solid integration test covering the sensing layer.

This test effectively validates the aggregation of multiple data sources (binary detection, shell history, and installation database). The JSON array format for packages aligns with the schema expected by _get_learned_patterns.


110-138: Comprehensive privacy hardening validation.

Good coverage of Zsh metadata stripping, environment variable assignments, and cross-platform path normalization. The double-escaped backslashes correctly simulate a Windows path in the history file.


194-227: Excellent Windows locking precision test.

This test validates the critical seek(0) requirement for deterministic Windows byte-range locking. The assertions confirm both the seek calls and the 1-byte lock parameter, which is essential for correct cross-platform behavior.


267-284: Thorough slug validation testing.

Good coverage of valid variants (including single-char "a" and uppercase slugs) and malicious inputs. The invalid slugs correctly test the regex boundaries for leading/trailing special characters and injection attempts.


353-389: Well-structured module reload test with proper isolation.

The use of reload_lock prevents race conditions during parallel test execution, and the cleanup in the finally block ensures other tests aren't affected. This is a necessary but tricky test for cross-platform import handling.


470-486: Good privacy boundary test.

This test validates the "safe harbor" logic that prevents leaking descriptive filenames that could contain sensitive project information. The 20-character limit is a reasonable threshold for command name complexity.

cortex/role_manager.py (10)

12-28: Clean cross-platform conditional imports.

The explicit type annotations (fcntl: ModuleType | None) and platform-specific import guards are well-structured. Only attempting to import msvcrt on Windows (line 22) is a sensible optimization.


31-50: Well-defined typed interface.

The SystemContext TypedDict provides a clear contract for the sensing layer output. Good documentation of the class purpose.


52-75: Comprehensive PII detection patterns.

Good coverage of credential types including cloud provider secrets (AWS, GCP, Azure), CI/CD tokens (GitHub, GitLab), and database connection strings. Precompilation is efficient for repeated pattern matching.


77-96: Good path isolation for testing.

The constructor properly isolates test paths from production by using env_path.parent as the base directory. This ensures history_db is also redirected during tests. As per coding guidelines, audit logging goes to ~/.cortex/history.db.


98-191: Well-implemented privacy-preserving shell history parsing.

Excellent layered approach to privacy: opt-out mechanism, PII redaction, environment variable stripping, path normalization, and command name length limits. The 15-command window balances recency with context.


193-249: Solid system sensing implementation.

Good coverage of binary signals across server software, ML tools, and DevOps utilities. The aggregation of shell patterns and learned installation patterns provides rich context for AI inference.


251-332: Robust role persistence with audit trail.

Good implementation with:

  • Strict input validation preventing injection
  • Atomic updates preserving user formatting
  • Audit logging to history.db as required by coding guidelines
  • Non-blocking audit failures to ensure primary operation succeeds

334-360: Tolerant role parsing.

Good defensive implementation that handles user-edited files with various formats (export prefix, quotes, comments) and corrupted data gracefully.


362-432: Correct cross-platform atomic file updates.

The implementation properly handles:

  • POSIX advisory locking via fcntl.flock
  • Windows byte-range locking with mandatory seek(0) for deterministic behavior
  • Atomic replacement via Path.replace() (same-directory guarantee)
  • Lock release in inner finally ensures no stale locks
  • Temp file cleanup in outer finally prevents orphaned files

434-505: Good learning loop implementation.

The method properly handles:

  • Missing database file (early return)
  • Malformed JSON data (skip and continue)
  • Deduplication while maintaining recency order
  • Appropriate logging levels (INFO for success, ERROR for failures)

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: 1

🤖 Fix all issues with AI agents
In @cortex/cli.py:
- Around line 274-296: The role method lacks audit logging for both 'detect' and
'set' actions; after a successful detect suggestion and after a successful role
save in role(self, args) (use action from getattr(args, "role_action") and
role_slug from args.role_slug), instantiate InstallationHistory and call
history.record_installation with an appropriate InstallationType (e.g.,
InstallationType.CONFIG or add a new type), the affected packages/roles list
(e.g., [role_slug] or detected roles), the executed command string(s) (e.g.,
[f"cortex role set {role_slug}"] or the detect invocation), and datetime.now(),
mirroring the pattern used in install(), so every role detect/set is recorded to
~/.cortex/history.db.
🧹 Nitpick comments (2)
cortex/cli.py (2)

329-335: Misleading comment about CLI parser.

The prompt instructs the AI that "FAILURE TO COMPLY WILL BREAK THE CLI PARSER," but the response from self.ask(question) is simply displayed to the user without any parsing. Consider either:

  1. Removing the misleading comment about breaking a parser, or
  2. Actually parsing the response if structured output is needed
-                f"--- STRICT RESPONSE FORMAT ---\n"
-                f"YOUR RESPONSE MUST START WITH THE NUMBER '1.' AND CONTAIN ONLY THE LIST. "
-                f"DO NOT PROVIDE INTRODUCTIONS. DO NOT PROVIDE REASONING. DO NOT PROVIDE A SUMMARY. "
-                f"FAILURE TO COMPLY WILL BREAK THE CLI PARSER.\n\n"
+                f"--- PREFERRED RESPONSE FORMAT ---\n"
+                f"Please start with '1.' and provide only the list of roles. "
+                f"Omit introductions, reasoning, and summaries.\n\n"

391-391: Consider adding a helpful error message for the fallback case.

While this line should be unreachable in normal operation (argparse restricts to detect/set), adding an error message would aid debugging if reached:

+        else:
+            self._print_error(f"Unknown role action: {action}")
         return 1
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f723f71 and 70086a7.

📒 Files selected for processing (1)
  • cortex/cli.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Follow PEP 8 style guide for Python code
Include type hints in Python code
Add docstrings for all public APIs in Python code
Use dry-run mode by default for all installation operations
Do not use silent sudo - require explicit user confirmation for privilege escalation
Implement Firejail sandboxing for execution of untrusted code
Log all operations to ~/.cortex/history.db for audit purposes

Files:

  • cortex/cli.py
⏰ 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). (3)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.10)
  • GitHub Check: test (3.11)
🔇 Additional comments (5)
cortex/cli.py (5)

6-6: LGTM!

The new imports are appropriate and both are used within the role method.

Also applies to: 27-27


347-389: LGTM!

The set action has proper validation and error handling for both ValueError (invalid slug) and RuntimeError (persistence failure). The request ID generation combines a timestamp with a short UUID suffix, which provides sufficient uniqueness for session tracking purposes.


2159-2160: LGTM!

The help table entries for role and stack commands are clear and consistent with the existing format.


2330-2351: LGTM!

The argparse definitions for the role command are well-structured with clear help strings and appropriate inline comments explaining the purpose of each subcommand.


2666-2667: LGTM!

The command routing for role follows the established pattern and correctly delegates to the cli.role(args) method.

Copy link
Collaborator

@Anshgrover23 Anshgrover23 left a comment

Choose a reason for hiding this comment

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

@Kesavaraja67 Left some major comments.

@Anshgrover23 Anshgrover23 marked this pull request as draft January 13, 2026 13:14
@Kesavaraja67
Copy link
Contributor Author

@Anshgrover23 I have addressed the mentioned changes and also updated the PR description video and attached the video below :

Video.Project.5.mp4

@Kesavaraja67 Kesavaraja67 marked this pull request as ready for review January 13, 2026 16:18
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

🤖 Fix all issues with AI agents
In @cortex/cli.py:
- Around line 366-423: The 'set' branch calls self._get_api_key() and passes its
result into AskHandler without validating it, risking a None API key; update the
block around the calls to self._get_api_key(), self._get_provider(), and
AskHandler(...) to explicitly check the api_key (from _get_api_key) and if
missing call the same error path used elsewhere (print an error and return
non-zero) before constructing AskHandler and calling handler.ask(rec_question),
ensuring the flow uses the validated api_key and does not proceed when None.
- Around line 300-364: The code creates an AskHandler using a possibly None API
key from _get_api_key() which can cause runtime failures; before instantiating
AskHandler, check the result of self._get_api_key() and if it is None or empty,
emit a clear error message (via cx_print or console.print/processLogger), return
a non-zero exit code (or abort the detect flow) and avoid calling
AskHandler(provider=...) and handler.ask; ensure you reference _get_api_key(),
provider via _get_provider(), AskHandler, and handler.ask when implementing this
early validation and error path.
🧹 Nitpick comments (7)
docs/ROLES.md (2)

94-107: Documentation code snippet is incomplete and may confuse readers.

The Python snippet illustrating the atomic write pattern is missing context and doesn't match the actual implementation. It shows temp_file.replace(target) without showing where temp_file or target are defined, and omits the cross-platform Windows locking (msvcrt) that the implementation supports.

Consider either:

  1. Removing the code snippet and referring readers to the source
  2. Providing a complete, accurate example that matches the implementation

44-45: Hardcoded coverage percentage will become stale.

The "91.11%" coverage statistic will drift as the codebase evolves. Consider either removing the specific percentage or noting it was accurate at time of initial implementation.

tests/test_role_management.py (3)

57-108: Test setup creates DB in temp directory but RoleManager may look elsewhere.

The test seeds db_path = temp_cortex_dir / "history.db" but the RoleManager instance on line 70 derives history_db from env_path.parent. Since env_path = temp_cortex_dir / ".env", the manager's history_db will be temp_cortex_dir / "history.db" — which matches.

However, the test doesn't verify that context["has_install_history"] is True, which would confirm the learning loop correctly read the seeded database.

💡 Consider adding assertion for has_install_history
         # Verify SQLite learning loop sensing.
         assert "installed:docker-ce" in context["patterns"]
         assert "installed:kubectl" in context["patterns"]
+        # Confirm the learning loop detected installation history.
+        assert context["has_install_history"] is True

353-389: Module reload test is fragile and may cause test pollution.

This test manipulates sys.modules and reloads the module to test conditional imports. While the reload_lock helps with parallel execution, module reloads can still cause subtle issues:

  1. Other tests running concurrently might see the modified module state
  2. The finally block restores modules but relies on monkeypatch cleanup

Consider isolating this test in a subprocess or marking it to run serially.


409-426: Test creates temp file outside the locked write mechanism.

The breaking_modifier creates temp_cortex_dir / ".env.tmp" directly, but the actual _locked_read_modify_write method creates its own temp file. The assertion on line 426 checks that the externally-created file doesn't exist, but this doesn't actually test cleanup of the method's internal temp file.

The test logic is correct for verifying that the finally block in _locked_read_modify_write cleans up temp files, since the method will create .env.tmp before calling the modifier. However, the modifier's temp_file.touch() is redundant.

💡 Simplify the breaking modifier
     def breaking_modifier(content, key, value):
         """Modifier function that intentionally crashes after creating a temp file."""
-        temp_file = temp_cortex_dir / ".env.tmp"
-        temp_file.touch()
         raise RuntimeError("Unexpected crash during write")
cortex/role_manager.py (2)

55-78: Comprehensive PII redaction patterns.

The precompiled regex patterns cover a broad range of sensitive data including API keys, tokens, passwords, authorization headers, cloud provider credentials, and database connection strings. This is a solid privacy-hardening implementation.

Consider adding patterns for:

  • SSH keys in arguments (e.g., ssh -i /path/to/key)
  • JWT tokens (Base64-encoded with . separators)

266-269: Consider stricter minimum length for role slugs.

The regex [a-zA-Z0-9](?:[a-zA-Z0-9_-]*[a-zA-Z0-9])? allows single-character slugs like "a". While technically valid, this may be too permissive for meaningful role identifiers.

If intentional, this is fine. If you want to require at least 2 characters:

💡 Optional: Require minimum 2-character slugs
-        if not re.fullmatch(r"[a-zA-Z0-9](?:[a-zA-Z0-9_-]*[a-zA-Z0-9])?", role_slug):
+        if not re.fullmatch(r"[a-zA-Z0-9][a-zA-Z0-9_-]*[a-zA-Z0-9]|[a-zA-Z0-9]{2}", role_slug):

Or simpler:

-        if not re.fullmatch(r"[a-zA-Z0-9](?:[a-zA-Z0-9_-]*[a-zA-Z0-9])?", role_slug):
+        if len(role_slug) < 2 or not re.fullmatch(r"[a-zA-Z0-9](?:[a-zA-Z0-9_-]*[a-zA-Z0-9])?", role_slug):
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 70086a7 and 669a4b4.

📒 Files selected for processing (6)
  • README.md
  • cortex/cli.py
  • cortex/installation_history.py
  • cortex/role_manager.py
  • docs/ROLES.md
  • tests/test_role_management.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • README.md
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Follow PEP 8 style guide for Python code
Include type hints in Python code
Add docstrings for all public APIs in Python code
Use dry-run mode by default for all installation operations
Do not use silent sudo - require explicit user confirmation for privilege escalation
Implement Firejail sandboxing for execution of untrusted code
Log all operations to ~/.cortex/history.db for audit purposes

Files:

  • cortex/installation_history.py
  • cortex/cli.py
  • tests/test_role_management.py
  • cortex/role_manager.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Maintain test coverage above 80% for pull requests

Files:

  • tests/test_role_management.py
🧠 Learnings (1)
📚 Learning: 2026-01-12T20:51:13.817Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T20:51:13.817Z
Learning: Applies to **/*.py : Log all operations to ~/.cortex/history.db for audit purposes

Applied to files:

  • cortex/cli.py
  • cortex/role_manager.py
🧬 Code graph analysis (2)
cortex/cli.py (1)
cortex/role_manager.py (3)
  • RoleManager (44-507)
  • get_system_context (196-252)
  • save_role (254-332)
tests/test_role_management.py (1)
cortex/role_manager.py (5)
  • get_system_context (196-252)
  • _get_shell_patterns (101-194)
  • save_role (254-332)
  • get_saved_role (334-360)
  • _locked_read_modify_write (362-432)
🔇 Additional comments (15)
cortex/installation_history.py (1)

35-35: LGTM!

Clean addition of the CONFIG enum member to support audit logging of role management operations. This aligns with the coding guideline to log all operations to ~/.cortex/history.db.

tests/test_role_management.py (3)

17-34: LGTM!

Well-designed fixture providing hermetic filesystem isolation. This prevents tests from interacting with actual user configuration, which is essential for reliable CI/CD.


37-54: LGTM!

The role_manager fixture correctly leverages temp_cortex_dir to isolate all derived paths including history_db, ensuring complete test isolation.


267-284: Single-character slug "a" is valid but consider if this is intentional.

The test validates that "a" is a valid slug. While the regex [a-zA-Z0-9](?:[a-zA-Z0-9_-]*[a-zA-Z0-9])? technically allows single alphanumeric characters, this may be too permissive for meaningful role identifiers.

If single-character slugs should be rejected, update the regex to require a minimum length.

cortex/cli.py (3)

276-298: LGTM!

Well-structured method with clear docstring, proper subcommand handling, and early return for missing action. The implementation follows the existing CLI patterns.


351-358: Audit logging records role detection events appropriately.

Using InstallationType.CONFIG for role-related operations aligns with the coding guideline to log all operations to ~/.cortex/history.db. The logged command accurately reflects the user action.


2366-2387: LGTM!

Clean parser definitions for the role command group with appropriate help text. The role_slug argument for set correctly requires a value.

cortex/role_manager.py (8)

1-14: LGTM!

Clean imports with appropriate standard library modules. Type hints are properly included.


15-31: LGTM!

Conditional imports for cross-platform locking are well-structured. The explicit type annotations for fcntl and msvcrt as ModuleType | None satisfy type checkers while maintaining runtime flexibility.


34-42: LGTM!

The SystemContext TypedDict provides clear type documentation for the sensing layer output, improving code maintainability and IDE support.


80-99: LGTM!

The __init__ method correctly handles both production and test scenarios. Using env_path.parent as the base directory during tests ensures proper isolation of all derived paths.


101-194: Well-implemented privacy-preserving shell history extraction.

The method correctly:

  • Respects CORTEX_SENSE_HISTORY opt-out
  • Strips Zsh extended history metadata
  • Redacts sensitive patterns before processing
  • Uses errors="replace" for corrupted data resilience
  • Falls back to simple split on malformed quoting
  • Extracts only basenames to prevent path leakage
  • Maps known commands to generalized intents

254-332: Robust role persistence with audit logging.

The save_role method:

  • Validates slug format before proceeding
  • Uses atomic file update via _locked_read_modify_write
  • Preserves existing formatting (export prefix, quotes, comments)
  • Logs changes to history.db for audit compliance

The audit logging failure is properly handled as non-blocking, which prevents secondary failures from breaking the primary operation. Based on learnings, this aligns with the requirement to log all operations to ~/.cortex/history.db.


362-432: Solid cross-platform atomic file locking implementation.

Key strengths:

  • Creates lock file with proper permissions (0o600)
  • Writes non-empty byte for Windows byte-range locking compatibility
  • Uses seek(0) before msvcrt operations for deterministic locking
  • Implements write-to-temp-and-swap pattern for atomicity
  • Cleans up temp file in finally block

One consideration: the lock file is never cleaned up after operations. This is generally fine (lock files are small), but you may want to document this behavior.


434-507: LGTM!

The _get_learned_patterns method correctly:

  • Checks for database existence before connecting
  • Validates table existence before querying
  • Parses JSON package arrays safely
  • Maintains recency order while deduplicating
  • Limits output to 5 most recent unique packages
  • Logs sensing success for audit purposes

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

🤖 Fix all issues with AI agents
In @cortex/cli.py:
- Around line 423-427: The call to handler.ask(rec_question) in the set
subcommand lacks exception handling and can crash on provider errors; wrap the
AskHandler creation and its ask() invocation (referencing self._get_provider(),
AskHandler, and ask) in a try/except block that catches provider/AI errors
(e.g., Exception or a more specific provider error type), log or display a
user-friendly error via console or logger, and ensure the subcommand
returns/continues gracefully instead of propagating the exception.
- Around line 350-354: Wrap the AskHandler call and rendering in a try/except
block: call AskHandler(api_key=api_key, provider=provider) and
handler.ask(question) inside try, then console.print(Markdown(answer)) on
success; catch ValueError, RuntimeError, and ImportError raised by handler.ask
and handle them by logging or printing a clear error via console.print
(including the exception message) and then exit or return to avoid an unhandled
crash; ensure you reference AskHandler, handler.ask, and
console.print(Markdown(answer)) when applying the change.
🧹 Nitpick comments (1)
cortex/cli.py (1)

362-363: Consider using timezone-aware datetime for consistency.

datetime.now() returns a naive datetime, but role_manager.py uses datetime.now(timezone.utc) for audit logging (line 320 in relevant snippet). Using naive datetimes can cause issues when comparing timestamps across different parts of the system.

♻️ Suggested fix
+from datetime import datetime, timezone
...
             history.record_installation(
                 InstallationType.CONFIG,
                 ["system-detection"],
                 ["cortex role detect"],
-                datetime.now(),
+                datetime.now(timezone.utc),
             )
...
             history.record_installation(
                 InstallationType.CONFIG,
                 [role_slug],
                 [f"cortex role set {role_slug}"],
-                datetime.now(),
+                datetime.now(timezone.utc),
             )

Also applies to: 386-387

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 669a4b4 and 0c35a9c.

📒 Files selected for processing (1)
  • cortex/cli.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Follow PEP 8 style guide for Python code
Include type hints in Python code
Add docstrings for all public APIs in Python code
Use dry-run mode by default for all installation operations
Do not use silent sudo - require explicit user confirmation for privilege escalation
Implement Firejail sandboxing for execution of untrusted code
Log all operations to ~/.cortex/history.db for audit purposes

Files:

  • cortex/cli.py
🧠 Learnings (1)
📚 Learning: 2026-01-12T20:51:13.817Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T20:51:13.817Z
Learning: Applies to **/*.py : Log all operations to ~/.cortex/history.db for audit purposes

Applied to files:

  • cortex/cli.py
🧬 Code graph analysis (1)
cortex/cli.py (2)
cortex/role_manager.py (2)
  • get_system_context (196-252)
  • save_role (254-332)
cortex/first_run_wizard.py (1)
  • _print_error (778-780)
⏰ 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). (5)
  • GitHub Check: Test (Python 3.11)
  • GitHub Check: Test (Python 3.10)
  • GitHub Check: test (3.10)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
🔇 Additional comments (5)
cortex/cli.py (5)

6-6: LGTM!

All new imports (uuid, Markdown, RoleManager) are properly used in the new role management functionality.

Also applies to: 11-12, 29-29


2205-2206: LGTM!

Help table entries for role and stack commands are appropriately added with clear descriptions.


2376-2398: LGTM!

The argparse configuration for the role command follows existing patterns and provides clear help text for both detect and set subcommands.


2712-2713: LGTM!

Command routing for role follows the established pattern and correctly delegates to cli.role(args).


356-363: Good implementation of audit logging.

Both detect and set operations are properly recorded via InstallationHistory.record_installation(), complying with the coding guideline to log all operations to ~/.cortex/history.db. Additionally, the RoleManager.save_role() method records role changes to a separate role_changes table for audit purposes.

Also applies to: 380-387

Copy link
Contributor Author

@Kesavaraja67 Kesavaraja67 left a comment

Choose a reason for hiding this comment

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

Addressed the mentioned changes.

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: 1

🤖 Fix all issues with AI agents
In @cortex/cli.py:
- Line 318: Timestamps in the CLI are created as naive datetimes in the detect
flow but as UTC-aware datetimes in the set action; change all uses of
datetime.now() that build `timestamp` (e.g., in the detect subcommand and any
other places that set `timestamp`) to use timezone-aware values via
datetime.now(timezone.utc), add the timezone import if missing (from datetime
import timezone), and ensure any comparisons or parsing of stored timestamps
convert to UTC-aware datetimes (e.g., by using .replace(tzinfo=timezone.utc) or
.astimezone(timezone.utc)) so all timestamp generation and comparisons are
consistently UTC-aware.
🧹 Nitpick comments (1)
cortex/cli.py (1)

343-362: Consider extracting duplicate AI invocation logic into a helper method.

The pattern of obtaining API key, getting provider, creating AskHandler, calling ask(), and rendering Markdown with identical error handling is duplicated between detect (lines 343-362) and set (lines 425-444).

♻️ Suggested helper method
def _ask_ai_and_render(self, question: str) -> int:
    """Invoke AI with question and render response as Markdown.
    
    Returns:
        int: 0 on success, 1 on failure.
    """
    api_key = self._get_api_key()
    if not api_key:
        self._print_error(
            "No API key found. Please configure an API provider or use Ollama."
        )
        return 1
    provider = self._get_provider()
    try:
        handler = AskHandler(api_key=api_key, provider=provider)
        answer = handler.ask(question)
        console.print(Markdown(answer))
        return 0
    except ImportError as e:
        self._print_error(str(e))
        cx_print(
            "Install the required SDK or set CORTEX_PROVIDER=ollama for local mode.", "info"
        )
        return 1
    except (ValueError, RuntimeError) as e:
        self._print_error(str(e))
        return 1

Then in detect and set, replace the duplicate blocks with:

if self._ask_ai_and_render(question) != 0:
    return 1

Also applies to: 425-444

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c35a9c and 4557d1f.

📒 Files selected for processing (1)
  • cortex/cli.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Follow PEP 8 style guide for Python code
Include type hints in Python code
Add docstrings for all public APIs in Python code
Use dry-run mode by default for all installation operations
Do not use silent sudo - require explicit user confirmation for privilege escalation
Implement Firejail sandboxing for execution of untrusted code
Log all operations to ~/.cortex/history.db for audit purposes

Files:

  • cortex/cli.py
🧠 Learnings (1)
📚 Learning: 2026-01-12T20:51:13.817Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T20:51:13.817Z
Learning: Applies to **/*.py : Log all operations to ~/.cortex/history.db for audit purposes

Applied to files:

  • cortex/cli.py
🧬 Code graph analysis (1)
cortex/cli.py (2)
cortex/role_manager.py (3)
  • RoleManager (44-507)
  • get_system_context (196-252)
  • save_role (254-332)
cortex/installation_history.py (2)
  • record_installation (259-317)
  • InstallationType (27-35)
⏰ 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). (6)
  • GitHub Check: Test (Python 3.11)
  • GitHub Check: Test (Python 3.12)
  • GitHub Check: Test (Python 3.10)
  • GitHub Check: test (3.10)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.12)
🔇 Additional comments (6)
cortex/cli.py (6)

6-12: LGTM!

Imports are appropriate for the new role management functionality. The Markdown import from rich.markdown enables proper rendering of AI responses, and timezone supports timestamp consistency.

Also applies to: 29-29


276-298: LGTM!

Method structure follows the established pattern for CLI subcommand handlers. Proper docstring with type hints as per coding guidelines, and safe handling of missing action.


379-454: LGTM!

The set action properly validates input, handles both ValueError and RuntimeError from save_role(), and logs the operation to history.db for audit compliance. The error handling for unknown commands is correctly structured.


2222-2223: LGTM!

Help table entries are concise and follow the existing style.


2393-2414: LGTM!

Parser definitions follow the established pattern for subcommand groups. The role_slug argument includes helpful examples in the help text.


2729-2730: LGTM!

Command routing correctly delegates to cli.role(args).

@sonarqubecloud
Copy link

@Kesavaraja67
Copy link
Contributor Author

@Anshgrover23 Addressed all the suggestions mentioned by the coderabbit and the PR is ready for the final review.

@Anshgrover23 Anshgrover23 changed the title feat: implement system role management and package recommendations feat: system role management and package recommendations Jan 13, 2026
Copy link
Collaborator

@Anshgrover23 Anshgrover23 left a comment

Choose a reason for hiding this comment

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

LGTM!

@Anshgrover23 Anshgrover23 merged commit 1bc0d78 into cortexlinux:main Jan 13, 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.

Package Recommendation Based on System Role

3 participants