Skip to content

feat(cli): Add comprehensive CLI command groups for API coverage - #190

Merged
frankbria merged 4 commits into
mainfrom
feature/cli-comprehensive-api-coverage
Jan 5, 2026
Merged

feat(cli): Add comprehensive CLI command groups for API coverage#190
frankbria merged 4 commits into
mainfrom
feature/cli-comprehensive-api-coverage

Conversation

@frankbria

@frankbria frankbria commented Jan 5, 2026

Copy link
Copy Markdown
Owner

Summary

  • Implements complete CLI command structure with 12 command groups covering all API endpoints
  • Phase 1 (Core workflows): auth, projects, blockers, checkpoints, discovery
  • Phase 2 (Agent & task management): agents, tasks, quality-gates, metrics, session, context, review
  • All commands developed using TDD approach with 157 tests passing

Features

Command Group Commands Description
auth login, logout, register, whoami, status Authentication management
projects list, create, get, status, tasks, activity, start, pause, resume Project CRUD & lifecycle
blockers list, resolve, skip, metrics Blocker resolution workflow
checkpoints list, create, restore Checkpoint management
discovery start, progress, answer, restart, generate-prd Discovery workflow
agents list, assign, remove, status, role Agent lifecycle management
tasks list, create, get, update Task CRUD operations
quality-gates get, run Quality gate checks
metrics tokens, costs, agent Usage & cost metrics
session get Session state management
context get, stats, flash-save, checkpoints Agent context management
review status, stats, findings, list Code review management

Technical Details

  • APIClient with retry logic and exponential backoff
  • Token-based auth with credentials stored in ~/.codeframe/credentials.json
  • Rich terminal output with tables, colors, and emoji indicators
  • JSON output format option for all commands (for scripting)

Test plan

  • All 157 CLI tests pass (uv run pytest tests/cli/ -v)
  • CLI imports successfully (from codeframe.cli import app)
  • Help output shows all 12 command groups
  • Manual verification of key workflows

Summary by CodeRabbit

  • New Features

    • Full CLI added covering projects, tasks, agents, sessions, checkpoints (deprecated alias preserved), blockers, discovery, reviews, quality gates, metrics, context, and auth; includes dashboard serve (port validation, auto-open, reload), clear-session, and version commands.
    • Built-in HTTP client with retries and centralized auth/token handling and secure local token storage.
  • Tests

    • Extensive test suites for CLI commands and the API client covering success, error, and edge cases.

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

Implement complete CLI command structure with 12 command groups:

Phase 1 (Core workflows):
- auth: login, logout, register, whoami, status
- projects: list, create, get, status, tasks, activity, start, pause, resume
- blockers: list, resolve, skip, metrics
- checkpoints: list, create, restore
- discovery: start, progress, answer, restart, generate-prd

Phase 2 (Agent & task management):
- agents: list, assign, remove, status, role
- tasks: list, create, get, update
- quality-gates: get, run
- metrics: tokens, costs, agent
- session: get
- context: get, stats, flash-save, checkpoints
- review: status, stats, findings, list

All commands follow TDD approach with 157 tests passing.
Includes APIClient with retry logic, auth token management,
and Rich-based terminal output formatting.
@coderabbitai

coderabbitai Bot commented Jan 5, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a Typer-based CLI (top-level app + many subcommand groups), an HTTP API client with retries and auth/error mapping, JWT token file/env handling, a dashboard serve command with port checks and uvicorn start, numerous command modules (auth, projects, agents, blockers, checkpoints, discovery, tasks, quality-gates, metrics, session, context, review), shared CLI helpers, and comprehensive tests for the CLI surface.

Changes

Cohort / File(s) Summary
Core CLI & infra
codeframe/cli/__init__.py, codeframe/cli/api_client.py, codeframe/cli/helpers.py, codeframe/cli/auth.py
New Typer app export app with many top-level commands (init/start/pause/resume/status/chat/config/checkpoint/serve/clear-session/version); APIClient with base URL resolution, token injection, retry/backoff, response -> APIError/AuthenticationError; shared console and require_auth helper; JWT token file storage and CODEFRAME_TOKEN precedence.
Serve/dashboard
codeframe/cli/__init__.py (serve command)
New serve command: port range validation, port-availability check, optional browser auto-open, runs uvicorn dashboard with optional reload; prints errors and exits non-zero on failure.
Auth module & commands
codeframe/cli/auth.py, codeframe/cli/auth_commands.py, tests/cli/test_auth_module.py, tests/cli/test_auth_commands.py
Token storage/clear/get/is_authenticated; CLI commands: login/logout/register/whoami with server interaction, token persistence, and tests covering interactive and error flows.
Agent management
codeframe/cli/agents_commands.py, tests/cli/test_agents_commands.py
New agents Typer group (agents_app) with list/assign/remove/status/role; table/json outputs, force confirmations, role updates, and tests covering prompts and API interactions.
Projects
codeframe/cli/project_commands.py, tests/cli/test_project_commands.py
Projects Typer group with list/create/get/status/tasks/activity/start/pause/resume; table/json outputs, pagination/filters, conflict/404 handling, and extensive tests including payload assertions.
Blockers
codeframe/cli/blocker_commands.py, tests/cli/test_blocker_commands.py
Blocker management Typer app: list/get/resolve/metrics with status filters and metrics output; tests for success/error cases.
Checkpoints
codeframe/cli/checkpoint_commands.py, tests/cli/test_checkpoint_commands.py
Checkpoints Typer app: list/create/get/delete/restore/diff with preview/confirm semantics and diff rendering; tests for interactive and non-interactive paths.
Discovery
codeframe/cli/discovery_commands.py, tests/cli/test_discovery_commands.py
Discovery Typer app: start/progress/answer/restart/generate-prd; progress and Q/A flow handling; tests for discovering/completed/idle states and restart/generate paths.
Context
codeframe/cli/context_commands.py, tests/cli/test_context_commands.py
Agent context Typer app: get/stats/flash-save/checkpoints with table/json outputs; tests cover each command.
Metrics
codeframe/cli/metrics_commands.py, tests/cli/test_metrics_commands.py
Metrics Typer app: tokens/costs/agent views, formatting helpers, table/JSON outputs; tests for aggregated and agent metrics.
Quality gates
codeframe/cli/quality_gates_commands.py, tests/cli/test_quality_gates_commands.py
Quality-gates Typer app: get/run with optional gate filter and status rendering; tests for success and 404 cases.
Review
codeframe/cli/review_commands.py, tests/cli/test_review_commands.py
Review Typer app: status/stats/findings/list with severity filters and formatted outputs; tests for populated and empty states.
Session & Tasks
codeframe/cli/session_commands.py, codeframe/cli/tasks_commands.py, tests/cli/test_session_commands.py, tests/cli/test_tasks_commands.py
Session Typer app (get, clear-session alias), Tasks Typer app (list/create/get/update) with require_auth and tests for success/error scenarios.
Test infra
tests/cli/__init__.py, tests/cli/test_api_client.py
Test package init and extensive APIClient tests covering base URL resolution, headers, error mapping, retry behavior, and all standard HTTP methods.

Sequence Diagram(s)

sequenceDiagram
    participant User as CLI User
    participant CLI as Typer CLI (app)
    participant Auth as Local Auth (file / env)
    participant API as Backend API
    participant Server as Uvicorn Server
    participant Browser as System Browser

    rect rgb(230,245,255)
      Note right of CLI: Login + token persistence
      User->>CLI: login --email user --password pwd
      CLI->>API: POST /auth/jwt/login
      API-->>CLI: 200 {access_token: jwt}
      CLI->>Auth: store_token(jwt)
      Auth-->>CLI: token persisted
      CLI-->>User: "Login successful"
    end

    rect rgb(245,255,230)
      Note right of CLI: Authenticated API call flow
      User->>CLI: projects list
      CLI->>Auth: get_token() -> jwt
      CLI->>API: GET /api/projects (Authorization: Bearer jwt)
      API-->>CLI: 200 [projects]
      CLI-->>User: formatted table/json
    end

    rect rgb(255,245,230)
      Note right of CLI: Serve dashboard flow
      User->>CLI: serve --port 8080 --open-browser
      CLI->>CLI: validate port range & availability
      CLI->>Server: start uvicorn host:port (reload?)
      Server-->>CLI: running
      alt open_browser true
        CLI->>Browser: open http://host:port
      end
      CLI-->>User: "Serving on http://host:port"
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I hopped through code with nimble paws,

Commands sprouted up without a pause,
Tokens snug in burrowed files,
Dashboards, agents, tests and smiles,
Hip-hop hooray — the CLI applause!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main addition: comprehensive CLI command groups with API coverage. It is specific, clear, and directly related to the primary changeset.
Docstring Coverage ✅ Passed Docstring coverage is 99.10% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/cli-comprehensive-api-coverage

Comment @coderabbitai help to get the list of available commands and usage tips.

@frankbria frankbria linked an issue Jan 5, 2026 that may be closed by this pull request
@claude

claude Bot commented Jan 5, 2026

Copy link
Copy Markdown

Code Review: CLI Comprehensive API Coverage

I've reviewed this comprehensive CLI implementation. Overall, this is excellent work with strong test coverage (157 passing tests), clean architecture, and good adherence to project standards. Here are my findings:

✅ Strengths

  1. Excellent TDD Approach: 157 tests with comprehensive coverage of command groups, API client, and auth module
  2. Clean Architecture: Well-organized separation of concerns across 12 command groups
  3. User Experience: Rich terminal output with tables, colors, and helpful error messages
  4. Error Handling: Robust retry logic with exponential backoff and clear error messages
  5. Security: Proper token storage with file permissions (0o600) and environment variable override
  6. Documentation: Clear docstrings and usage examples in all command modules

🔍 Issues Found

1. Security: Credentials File Permissions (codeframe/cli/auth.py:54)

Severity: Medium

The current implementation sets file permissions after writing sensitive data:

# Write to file
with open(creds_path, "w") as f:
    json.dump(credentials, f, indent=2)

# Set secure permissions (owner read/write only)
creds_path.chmod(0o600)

Issue: There's a brief window where the file exists with default permissions (often 0o644), potentially exposing the JWT token.

Fix: Use os.open() with proper flags to set permissions atomically:

import os

# Create file with secure permissions atomically
fd = os.open(creds_path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
with os.fdopen(fd, 'w') as f:
    json.dump(credentials, f, indent=2)

2. Error Handling: Unused Variable (codeframe/cli/api_client.py:184)

Severity: Low

last_exception = None

for attempt in range(self.max_retries):
    try:
        # ...
    except requests.ConnectionError as e:
        last_exception = e  # Stored but never used

Issue: last_exception is tracked but not included in the final error message.

Fix: Include exception details in the final error:

# All retries exhausted
raise APIError(
    f"Connection error: Unable to connect to {self.base_url}. "
    f"Please check the server is running and try again. "
    f"Last error: {last_exception}",
    status_code=None,
)

3. Potential Issue: Missing requests.RequestException Handling

Severity: Low

The retry logic only catches ConnectionError and Timeout, but other network errors could occur (e.g., TooManyRedirects, URLRequired, etc.).

Recommendation: Add a catch-all for requests.RequestException:

except (requests.ConnectionError, requests.Timeout) as e:
    # Existing retry logic
    
except requests.RequestException as e:
    # Don't retry for other request errors
    raise APIError(f"Request failed: {e}", status_code=None)

💡 Suggestions

1. API Client: Consider Adding Response Caching

For commands like codeframe projects list, adding short-lived caching (e.g., 30 seconds) could improve UX when users run multiple commands quickly.

2. Auth: Add Token Expiration Check

The auth module could decode the JWT (without verification) to check expiration and proactively prompt re-login:

import jwt
from datetime import datetime

def is_token_expired(token: str) -> bool:
    try:
        payload = jwt.decode(token, options={"verify_signature": False})
        exp = payload.get("exp")
        if exp:
            return datetime.fromtimestamp(exp) < datetime.now()
    except:
        pass
    return False

3. CLI: Add Command Aliases

Consider adding short aliases for frequently used commands:

  • cf p listcodeframe projects list
  • cf a assigncodeframe agents assign

This can be done by adding aliases to the Typer app configuration.

4. Testing: Add Integration Tests

While unit tests are excellent, consider adding integration tests that start a test server and verify end-to-end flows:

  • Login → Create Project → Assign Agent → List Tasks

📊 Code Quality Metrics

  • Test Coverage: 157/157 tests passing (100%)
  • Code Organization: ⭐⭐⭐⭐⭐ (5/5) - Clear separation of concerns
  • Error Handling: ⭐⭐⭐⭐ (4/5) - Minor gaps in exception coverage
  • Security: ⭐⭐⭐⭐ (4/5) - File permission race condition
  • Documentation: ⭐⭐⭐⭐⭐ (5/5) - Excellent docstrings and examples

✅ Approval Recommendation

APPROVED with minor fixes recommended. The security issue should be addressed before merge, but it's not critical for internal testing. The other issues are low-priority improvements.

🎯 Next Steps

  1. Fix the credentials file permission race condition
  2. Update error message to include last_exception
  3. Consider adding the suggested enhancements in a follow-up PR

Great work on this comprehensive CLI implementation! The TDD approach and attention to UX really shows. 🚀

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 @codeframe/cli/__init__.py:
- Around line 168-174: The top-level stub command checkpoint in the CLI (the
function checkpoint decorated with @app.command()) conflicts with the full
checkpoints sub-app; remove the redundant stub or convert it into a deprecation
shim: delete or comment out the checkpoint function entirely, or modify it to
print a clear deprecation/warning message directing users to use the checkpoints
subcommand (e.g., "Use `codeframe checkpoints ...`") and return a non-error
exit, ensuring you reference the existing checkpoint function name and
@app.command() decorator when making the change.
🧹 Nitpick comments (27)
tests/cli/test_auth_commands.py (1)

1-223: Excellent test coverage for auth commands!

The test suite is comprehensive and well-structured:

  • Covers all auth commands (login, logout, register, whoami)
  • Tests both success and error paths
  • Validates prompting behavior
  • Properly isolates tests with mocking and tmp_path
  • Verifies token storage and retrieval side effects

Optional: Consider extracting common test fixtures.

The credential setup pattern is repeated across many tests. Consider creating a pytest fixture to reduce duplication:

💡 Optional refactor to reduce duplication
@pytest.fixture
def mock_credentials(tmp_path):
    """Fixture providing mocked credentials path with valid token."""
    creds_path = tmp_path / ".codeframe" / "credentials.json"
    creds_path.parent.mkdir(parents=True)
    with open(creds_path, "w") as f:
        json.dump({"access_token": "valid-token"}, f)
    
    with patch("codeframe.cli.auth.get_credentials_path", return_value=creds_path):
        yield creds_path

Then tests can use: def test_whoami_authenticated(self, mock_credentials):

tests/cli/test_metrics_commands.py (1)

1-105: LGTM! Well-structured metrics command tests.

The test suite properly validates the metrics commands:

  • Tests tokens, costs, and agent metrics endpoints
  • Mocks API responses appropriately
  • Verifies output contains expected data
  • Properly isolates tests with credential mocking

Optional: Similar duplication pattern as auth tests.

The credential setup code is repeated across test methods. Consider using the same fixture pattern suggested in test_auth_commands.py to reduce duplication across the entire test suite.

tests/cli/test_agents_commands.py (1)

1-201: Excellent agent command test coverage!

The test suite thoroughly validates agent management operations:

  • Covers all CRUD operations for agents
  • Tests interactive prompts (remove without --force)
  • Validates request payloads (lines 109-110)
  • Handles edge cases like empty agent lists
  • Properly tests role assignment and updates

The verification of request payload at lines 109-110 is particularly good practice, ensuring the role parameter is properly sent to the API.

Optional: Extract credential setup fixture.

Same duplication pattern noted in previous files. A shared fixture would improve maintainability across the entire CLI test suite.

tests/cli/test_quality_gates_commands.py (1)

21-111: Consider extracting credentials setup to a pytest fixture.

The credentials file creation pattern is repeated in all test methods. A fixture would reduce duplication and improve maintainability:

💡 Suggested refactor using pytest fixture

Add a fixture at the module level:

@pytest.fixture
def mock_credentials(tmp_path):
    """Create mock credentials file."""
    creds_path = tmp_path / ".codeframe" / "credentials.json"
    creds_path.parent.mkdir(parents=True)
    with open(creds_path, "w") as f:
        json.dump({"access_token": "valid-token"}, f)
    return creds_path

Then simplify each test:

-    def test_get_quality_gates_success(self, tmp_path):
+    def test_get_quality_gates_success(self, mock_credentials):
         """Get should display quality gate status for task."""
-        creds_path = tmp_path / ".codeframe" / "credentials.json"
-        creds_path.parent.mkdir(parents=True)
-        with open(creds_path, "w") as f:
-            json.dump({"access_token": "valid-token"}, f)

         mock_response = MagicMock()
         # ... rest of test ...
         
-        with patch("codeframe.cli.auth.get_credentials_path", return_value=creds_path):
+        with patch("codeframe.cli.auth.get_credentials_path", return_value=mock_credentials):

Apply this pattern to all test methods.

tests/cli/test_context_commands.py (1)

21-128: Apply the same fixture refactoring as suggested for quality_gates tests.

This file follows the same pattern of duplicating credentials setup across all test methods. The pytest fixture approach suggested for test_quality_gates_commands.py applies here as well.

tests/cli/test_api_client.py (1)

25-31: Remove redundant os.environ.pop() call.

The patch.dict(os.environ, {}, clear=True) already clears all environment variables, making the subsequent os.environ.pop("CODEFRAME_API_URL", None) redundant.

🔎 Suggested simplification
     def test_default_url(self):
         """Default URL should be localhost:8080."""
         with patch.dict(os.environ, {}, clear=True):
-            # Remove any existing CODEFRAME_API_URL
-            os.environ.pop("CODEFRAME_API_URL", None)
             url = get_api_base_url()
         assert url == "http://localhost:8080"
tests/cli/test_session_commands.py (1)

21-62: Apply credentials fixture pattern to reduce duplication.

As with the other test files, the credentials setup is duplicated. Consider using the pytest fixture approach suggested in test_quality_gates_commands.py.

tests/cli/test_checkpoint_commands.py (1)

21-284: Apply credentials fixture pattern across all 11 test methods.

This file has the most duplication of the credentials setup pattern. The pytest fixture approach would provide the greatest benefit here, reducing 11 repetitions to a single fixture definition.

codeframe/cli/metrics_commands.py (1)

33-38: Extract duplicated require_auth helper to a shared module.

The require_auth function is duplicated across at least 8 CLI command modules (metrics, session, review, context, project, agents, discovery, checkpoint). This violates the DRY principle and makes maintenance harder.

🔎 Recommended refactor

Create a shared utility module (e.g., codeframe/cli/utils.py or codeframe/cli/common.py):

# codeframe/cli/utils.py
from rich.console import Console
import typer
from codeframe.cli.api_client import APIClient

console = Console()

def require_auth(client: APIClient):
    """Check if client is authenticated, exit with error if not."""
    if not client.token:
        console.print("[yellow]Not logged in.[/yellow]")
        console.print("Please log in: codeframe auth login")
        raise typer.Exit(1)

Then import it in each command module:

-def require_auth(client: APIClient):
-    """Check if client is authenticated, exit with error if not."""
-    if not client.token:
-        console.print("[yellow]Not logged in.[/yellow]")
-        console.print("Please log in: codeframe auth login")
-        raise typer.Exit(1)
+from codeframe.cli.utils import require_auth

Based on relevant code snippets showing identical implementations across multiple modules.

codeframe/cli/auth.py (1)

32-57: Minor: Consider atomic file creation with secure permissions.

There's a brief window between file creation and chmod(0o600) where the file has default permissions. For a CLI tool storing tokens in the user's home directory, this is acceptable, but for higher-security contexts, consider atomic creation.

🔎 Optional: Atomic secure file creation
-    # Write to file
-    with open(creds_path, "w") as f:
-        json.dump(credentials, f, indent=2)
-
-    # Set secure permissions (owner read/write only)
-    creds_path.chmod(0o600)
+    import os
+    # Atomic creation with secure permissions
+    fd = os.open(creds_path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
+    try:
+        with os.fdopen(fd, "w") as f:
+            json.dump(credentials, f, indent=2)
+    except:
+        os.close(fd)
+        raise
codeframe/cli/quality_gates_commands.py (1)

33-39: Consider extracting require_auth to a shared module.

The require_auth function is duplicated across multiple command modules (tasks_commands.py, agents_commands.py, etc.). Consider extracting it to a shared utilities module to maintain DRY principles.

Based on the relevant code snippets, this same function exists in codeframe/cli/tasks_commands.py at lines 35-40.

🔎 Proposed refactor

Create a shared module (e.g., codeframe/cli/utils.py):

# codeframe/cli/utils.py
import typer
from rich.console import Console
from codeframe.cli.api_client import APIClient

console = Console()

def require_auth(client: APIClient):
    """Check if client is authenticated, exit with error if not."""
    if not client.token:
        console.print("[yellow]Not logged in.[/yellow]")
        console.print("Please log in: codeframe auth login")
        raise typer.Exit(1)

Then import in each command module:

from codeframe.cli.utils import require_auth
codeframe/cli/discovery_commands.py (2)

23-23: Unused imports from rich.progress.

Progress, SpinnerColumn, and TextColumn are imported but never used in this module. Consider removing them to keep the imports clean.

🔎 Proposed fix
-from rich.progress import Progress, SpinnerColumn, TextColumn

38-43: Duplicate require_auth helper across CLI modules.

This exact function is duplicated in at least 7 modules (agents_commands, metrics_commands, session_commands, context_commands, checkpoint_commands, blocker_commands, project_commands). Consider extracting it to a shared utility module (e.g., codeframe/cli/utils.py) to improve maintainability.

🔎 Suggested shared utility

Create codeframe/cli/utils.py:

import typer
from rich.console import Console
from codeframe.cli.api_client import APIClient

console = Console()

def require_auth(client: APIClient):
    """Check if client is authenticated, exit with error if not."""
    if not client.token:
        console.print("[yellow]Not logged in.[/yellow]")
        console.print("Please log in: codeframe auth login")
        raise typer.Exit(1)

Then import in each command module:

from codeframe.cli.utils import require_auth
codeframe/cli/checkpoint_commands.py (2)

38-43: Duplicate require_auth helper.

Same duplication issue as noted in discovery_commands.py. Extract to a shared utility.


205-242: Delete command uses --force but restore uses --confirm - consider consistency.

The delete command uses --force to skip confirmation, while restore uses --confirm to perform the action. This inconsistency may confuse users. Consider aligning the flag semantics or documenting the difference clearly.

codeframe/cli/__init__.py (2)

232-245: Fixed 1.5s delay before opening browser may be insufficient.

The hardcoded time.sleep(1.5) assumes the server starts within 1.5 seconds. On slower machines or under load, this may fail. Consider implementing a health-check loop with timeout instead.

🔎 Suggested improvement
def open_in_browser():
    """Open browser after server is ready."""
    import urllib.request
    max_wait = 10  # seconds
    for _ in range(max_wait * 2):
        try:
            urllib.request.urlopen(f"http://localhost:{port}/health", timeout=0.5)
            webbrowser.open(f"http://localhost:{port}")
            return
        except Exception:
            time.sleep(0.5)
    # Fallback: try anyway
    webbrowser.open(f"http://localhost:{port}")

298-312: Imports after code violates PEP 8 convention.

While this works, placing imports at the bottom of the file after function definitions is unconventional. Consider moving these imports to the top of the file with a comment explaining they're deferred to avoid circular imports (if that's the reason), or restructure to follow standard conventions.

tests/cli/test_discovery_commands.py (1)

21-42: Consider using a pytest fixture to reduce credential setup duplication.

The credential file creation code is repeated in every test method. A shared fixture would improve maintainability.

🔎 Suggested fixture
@pytest.fixture
def mock_credentials(tmp_path):
    """Create mock credentials file and return the path."""
    creds_path = tmp_path / ".codeframe" / "credentials.json"
    creds_path.parent.mkdir(parents=True)
    with open(creds_path, "w") as f:
        json.dump({"access_token": "valid-token"}, f)
    return creds_path

Then use in tests:

def test_start_discovery_success(self, mock_credentials):
    mock_response = MagicMock()
    # ...
    with patch("codeframe.cli.auth.get_credentials_path", return_value=mock_credentials):
        # ...
codeframe/cli/blocker_commands.py (1)

37-42: Duplicate require_auth helper.

Same duplication issue as noted previously. Extract to a shared utility.

codeframe/cli/api_client.py (2)

162-220: last_exception is captured but never used.

The variable last_exception is assigned on lines 198 and 208 but is never used in the final error message. Consider including it for debugging purposes or remove the variable.

🔎 Proposed fix
         # All retries exhausted
         raise APIError(
             f"Connection error: Unable to connect to {self.base_url}. "
-            "Please check the server is running and try again.",
+            f"Please check the server is running and try again. Last error: {last_exception}",
             status_code=None,
         )

197-213: Consider adding jitter to exponential backoff to prevent thundering herd.

When multiple CLI instances retry simultaneously (e.g., in CI), pure exponential backoff can cause synchronized retry storms. Adding random jitter is a common best practice.

🔎 Suggested improvement
import random

# In the retry loop:
if attempt < self.max_retries - 1:
    # Exponential backoff with jitter
    base_delay = 2 ** attempt
    jitter = random.uniform(0, base_delay * 0.1)
    time.sleep(base_delay + jitter)
codeframe/cli/project_commands.py (2)

41-46: Duplicate require_auth helper.

Same duplication issue as noted in other modules. Extract to a shared utility.


99-102: Redundant login hint after AuthenticationError.

The AuthenticationError message already includes login guidance (per api_client.py line 129). The additional console.print on line 101 is redundant.

🔎 Proposed fix
     except AuthenticationError as e:
         console.print(f"[red]Authentication error:[/red] {e}")
-        console.print("Please log in: codeframe auth login")
         raise typer.Exit(1)
tests/cli/test_blocker_commands.py (4)

15-15: Consider using a pytest fixture for the runner.

While the module-level runner works, a pytest fixture would be more consistent with patterns used elsewhere (see test_cli_session.py) and better for test isolation.

🔎 Suggested refactor
-runner = CliRunner()
+
+@pytest.fixture
+def runner():
+    """Create CLI test runner."""
+    return CliRunner()

Then update test methods to accept runner as a parameter.


18-84: Consider a shared fixture for credential setup.

The credential file setup pattern (lines 23-26, 49-52, 67-70) is repeated across all tests. Extract this into a pytest fixture to reduce duplication.

🔎 Suggested fixture
@pytest.fixture
def mock_credentials(tmp_path):
    """Create mock credentials file."""
    creds_path = tmp_path / ".codeframe" / "credentials.json"
    creds_path.parent.mkdir(parents=True)
    with open(creds_path, "w") as f:
        json.dump({"access_token": "valid-token"}, f)
    return creds_path

Then use it in tests:

def test_list_blockers_success(self, mock_credentials):
    # ...
    with patch("codeframe.cli.auth.get_credentials_path", return_value=mock_credentials):
        # ...

139-160: Consider verifying the request payload.

The test confirms the command succeeds but doesn't verify that the answer "Use PostgreSQL" is included in the request body sent to the API. While not critical, this would make the test more thorough.

🔎 Example verification
     with patch("codeframe.cli.auth.get_credentials_path", return_value=creds_path):
         with patch("requests.request", return_value=mock_response) as mock_request:
             result = runner.invoke(blockers_app, ["resolve", "1", "Use PostgreSQL"])

     assert result.exit_code == 0
     assert "resolved" in result.output.lower()
+    
+    # Verify the answer was sent to the API
+    call_kwargs = mock_request.call_args.kwargs
+    assert call_kwargs.get("json", {}).get("answer") == "Use PostgreSQL"

229-231: Consider more specific output assertions.

The assertions check for "20" and "18" or "resolved" anywhere in the output, which are quite permissive. The test would pass even if the metrics aren't formatted correctly.

🔎 More specific assertions
     assert result.exit_code == 0
-    assert "20" in result.output  # total blockers
-    assert "18" in result.output or "resolved" in result.output.lower()
+    # Check for specific metrics in output
+    assert "total" in result.output.lower() and "20" in result.output
+    assert "resolved" in result.output.lower() and "18" in result.output
+    assert "pending" in result.output.lower() and "1" in result.output

This ensures the labels appear alongside the values, not just the values alone.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 867b772 and dab798e.

📒 Files selected for processing (30)
  • codeframe/cli/__init__.py
  • codeframe/cli/agents_commands.py
  • codeframe/cli/api_client.py
  • codeframe/cli/auth.py
  • codeframe/cli/auth_commands.py
  • codeframe/cli/blocker_commands.py
  • codeframe/cli/checkpoint_commands.py
  • codeframe/cli/context_commands.py
  • codeframe/cli/discovery_commands.py
  • codeframe/cli/metrics_commands.py
  • codeframe/cli/project_commands.py
  • codeframe/cli/quality_gates_commands.py
  • codeframe/cli/review_commands.py
  • codeframe/cli/session_commands.py
  • codeframe/cli/tasks_commands.py
  • tests/cli/__init__.py
  • tests/cli/test_agents_commands.py
  • tests/cli/test_api_client.py
  • tests/cli/test_auth_commands.py
  • tests/cli/test_auth_module.py
  • tests/cli/test_blocker_commands.py
  • tests/cli/test_checkpoint_commands.py
  • tests/cli/test_context_commands.py
  • tests/cli/test_discovery_commands.py
  • tests/cli/test_metrics_commands.py
  • tests/cli/test_project_commands.py
  • tests/cli/test_quality_gates_commands.py
  • tests/cli/test_review_commands.py
  • tests/cli/test_session_commands.py
  • tests/cli/test_tasks_commands.py
🧰 Additional context used
📓 Path-based instructions (1)
codeframe/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

codeframe/**/*.py: Use Python 3.11+ for backend development with FastAPI, AsyncAnthropic, SQLite with async support (aiosqlite), and tiktoken for token counting
Use token counting via tiktoken library for token budget management with ~50,000 token limit per conversation
Use asyncio patterns with AsyncAnthropic for async/await in Python backend for concurrent operations
Implement quality gates with multi-stage pre-completion checks (tests → type → coverage → review) and Git + SQLite + context snapshots for project state rollback
Use tiered memory system (HOT/WARM/COLD) with importance scoring using hybrid exponential decay algorithm for context management with 30-50% token reduction
Implement session lifecycle management with auto-save/restore using file-based storage at .codeframe/session_state.json

Files:

  • codeframe/cli/metrics_commands.py
  • codeframe/cli/session_commands.py
  • codeframe/cli/auth_commands.py
  • codeframe/cli/api_client.py
  • codeframe/cli/__init__.py
  • codeframe/cli/auth.py
  • codeframe/cli/quality_gates_commands.py
  • codeframe/cli/blocker_commands.py
  • codeframe/cli/context_commands.py
  • codeframe/cli/tasks_commands.py
  • codeframe/cli/discovery_commands.py
  • codeframe/cli/checkpoint_commands.py
  • codeframe/cli/review_commands.py
  • codeframe/cli/project_commands.py
  • codeframe/cli/agents_commands.py
🧠 Learnings (4)
📚 Learning: 2026-01-04T06:26:12.870Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T06:26:12.870Z
Learning: Applies to codeframe/**/*.py : Implement quality gates with multi-stage pre-completion checks (tests → type → coverage → review) and Git + SQLite + context snapshots for project state rollback

Applied to files:

  • tests/cli/test_quality_gates_commands.py
  • tests/cli/test_review_commands.py
  • codeframe/cli/quality_gates_commands.py
📚 Learning: 2026-01-04T06:26:12.870Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T06:26:12.870Z
Learning: Applies to codeframe/**/*.py : Implement session lifecycle management with auto-save/restore using file-based storage at .codeframe/session_state.json

Applied to files:

  • codeframe/cli/session_commands.py
📚 Learning: 2026-01-04T06:26:12.870Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T06:26:12.870Z
Learning: Applies to codeframe/auth/**/*.py : Organize Python backend files with Auth module at codeframe/auth/ containing dependencies.py (get_current_user), manager.py (UserManager), models.py, router.py, and schemas.py

Applied to files:

  • codeframe/cli/auth_commands.py
  • codeframe/cli/api_client.py
  • codeframe/cli/auth.py
📚 Learning: 2026-01-04T06:26:12.870Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T06:26:12.870Z
Learning: Applies to codeframe/auth/**/*.py : For authentication, use FastAPI Users with JWT tokens and mandatory authentication (no bypass mode)

Applied to files:

  • codeframe/cli/auth_commands.py
  • codeframe/cli/auth.py
🧬 Code graph analysis (22)
tests/cli/test_quality_gates_commands.py (1)
codeframe/cli/quality_gates_commands.py (1)
  • get (42-111)
tests/cli/test_context_commands.py (3)
codeframe/cli/api_client.py (1)
  • patch (258-268)
tests/cli/test_cli_session.py (1)
  • runner (19-21)
tests/cli/test_review_commands.py (1)
  • test_stats_success (71-93)
tests/cli/test_checkpoint_commands.py (2)
codeframe/cli/api_client.py (1)
  • patch (258-268)
tests/cli/test_cli_session.py (1)
  • runner (19-21)
codeframe/cli/metrics_commands.py (2)
codeframe/cli/api_client.py (4)
  • APIClient (54-279)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • get (222-232)
codeframe/cli/project_commands.py (2)
  • require_auth (41-46)
  • get (171-212)
tests/cli/test_auth_module.py (1)
codeframe/cli/auth.py (5)
  • get_credentials_path (23-29)
  • store_token (32-56)
  • get_token (59-99)
  • clear_token (102-113)
  • is_authenticated (116-122)
tests/cli/test_agents_commands.py (3)
codeframe/cli/api_client.py (1)
  • patch (258-268)
tests/cli/test_cli_session.py (1)
  • runner (19-21)
tests/cli/test_project_commands.py (1)
  • test_status_success (212-239)
tests/cli/test_review_commands.py (1)
tests/cli/test_cli_session.py (1)
  • runner (19-21)
tests/cli/test_api_client.py (1)
codeframe/cli/api_client.py (8)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • get_api_base_url (44-51)
  • _get_headers (76-87)
  • get (222-232)
  • post (234-244)
  • delete (270-279)
  • put (246-256)
tests/cli/test_auth_commands.py (3)
codeframe/cli/api_client.py (1)
  • patch (258-268)
tests/cli/test_cli_session.py (1)
  • runner (19-21)
codeframe/core/config.py (1)
  • load (223-235)
codeframe/cli/auth.py (2)
codeframe/cli/api_client.py (1)
  • get (222-232)
codeframe/cli/context_commands.py (1)
  • get (44-88)
tests/cli/test_project_commands.py (2)
codeframe/cli/api_client.py (1)
  • get (222-232)
codeframe/cli/project_commands.py (1)
  • get (171-212)
codeframe/cli/quality_gates_commands.py (2)
codeframe/cli/api_client.py (4)
  • APIClient (54-279)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • get (222-232)
codeframe/cli/tasks_commands.py (2)
  • require_auth (36-41)
  • get (182-224)
tests/cli/test_blocker_commands.py (2)
tests/cli/test_cli_session.py (1)
  • runner (19-21)
codeframe/cli/blocker_commands.py (1)
  • get (116-171)
codeframe/cli/blocker_commands.py (1)
codeframe/cli/api_client.py (5)
  • APIClient (54-279)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • get (222-232)
  • post (234-244)
tests/cli/test_metrics_commands.py (2)
codeframe/cli/api_client.py (1)
  • patch (258-268)
tests/cli/test_cli_session.py (1)
  • runner (19-21)
codeframe/cli/context_commands.py (5)
codeframe/cli/api_client.py (5)
  • APIClient (54-279)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • get (222-232)
  • post (234-244)
codeframe/cli/agents_commands.py (1)
  • require_auth (38-43)
codeframe/cli/checkpoint_commands.py (2)
  • require_auth (38-43)
  • get (153-202)
codeframe/cli/discovery_commands.py (1)
  • require_auth (38-43)
codeframe/cli/project_commands.py (2)
  • require_auth (41-46)
  • get (171-212)
tests/cli/test_tasks_commands.py (2)
codeframe/cli/api_client.py (2)
  • patch (258-268)
  • get (222-232)
codeframe/cli/tasks_commands.py (1)
  • get (182-224)
codeframe/cli/tasks_commands.py (1)
codeframe/cli/api_client.py (6)
  • APIClient (54-279)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • get (222-232)
  • post (234-244)
  • patch (258-268)
codeframe/cli/discovery_commands.py (8)
codeframe/cli/api_client.py (5)
  • APIClient (54-279)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • post (234-244)
  • get (222-232)
codeframe/cli/agents_commands.py (1)
  • require_auth (38-43)
codeframe/cli/blocker_commands.py (2)
  • require_auth (37-42)
  • get (116-171)
codeframe/cli/checkpoint_commands.py (2)
  • require_auth (38-43)
  • get (153-202)
codeframe/cli/context_commands.py (2)
  • require_auth (35-40)
  • get (44-88)
codeframe/cli/metrics_commands.py (1)
  • require_auth (33-38)
codeframe/cli/project_commands.py (3)
  • require_auth (41-46)
  • start (374-401)
  • get (171-212)
codeframe/cli/session_commands.py (1)
  • require_auth (34-39)
codeframe/cli/checkpoint_commands.py (2)
codeframe/cli/api_client.py (3)
  • APIClient (54-279)
  • APIError (29-35)
  • AuthenticationError (38-41)
codeframe/cli/tasks_commands.py (1)
  • require_auth (36-41)
codeframe/cli/project_commands.py (1)
codeframe/cli/api_client.py (5)
  • APIClient (54-279)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • get (222-232)
  • post (234-244)
codeframe/cli/agents_commands.py (1)
codeframe/cli/api_client.py (7)
  • APIClient (54-279)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • get (222-232)
  • post (234-244)
  • delete (270-279)
  • put (246-256)
⏰ 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). (2)
  • GitHub Check: E2E Smoke Tests (Chromium)
  • GitHub Check: claude-review
🔇 Additional comments (74)
tests/cli/__init__.py (1)

1-1: LGTM! Clean package initializer.

The package initializer correctly follows Python conventions with a descriptive docstring and no unnecessary code.

tests/cli/test_auth_module.py (1)

1-228: Excellent comprehensive unit tests for auth utilities!

The test suite provides thorough coverage of all auth utility functions:

Security considerations properly tested:

  • Lines 99-108: Validates file permissions are restricted to 0o600 (owner read/write only)

Environment variable precedence verified:

  • Lines 162-174: Confirms CODEFRAME_TOKEN env var takes precedence over file-based credentials

Edge cases well covered:

  • Invalid JSON handling
  • Missing keys in JSON
  • Non-existent files
  • Parent directory creation
  • Token overwriting

The test structure is excellent for TDD, validating each function's behavior comprehensively without unnecessary duplication.

tests/cli/test_quality_gates_commands.py (1)

94-111: Good practice validating the gate filter in the request payload.

The test correctly verifies that the --gate option is passed through to the API request body, ensuring the CLI properly forwards user options.

tests/cli/test_api_client.py (1)

278-293: Excellent retry logic testing.

The use of side_effect with a list to simulate a failed then successful request is a clean way to test retry behavior.

tests/cli/test_checkpoint_commands.py (2)

192-208: Good use of input parameter to test interactive prompts.

The test correctly simulates user confirmation by passing input="y\n" to the CLI runner, ensuring the interactive prompt path is tested without requiring actual user interaction.


93-113: Thorough validation of optional parameter propagation.

The test correctly verifies that the --description option is passed through to the API by inspecting the call arguments. This ensures CLI options are properly mapped to API requests.

codeframe/cli/metrics_commands.py (4)

41-43: LGTM!

The format_number helper correctly formats numbers with thousand separators using Python's built-in formatting. This improves readability of large token counts and costs.


46-106: LGTM!

The tokens command is well-implemented with:

  • Clear authentication enforcement
  • Proper error handling for 404 and other API errors
  • Support for both text and JSON output formats
  • Clean, user-friendly text formatting with token breakdown by agent

108-167: LGTM!

The costs command properly implements cost metrics display with:

  • Appropriate USD formatting (2 decimal places)
  • Safe slicing of the last 7 days (handles lists shorter than 7)
  • Consistent error handling pattern
  • Clear daily breakdown table

170-215: LGTM!

The agent command correctly implements agent-specific metrics with comprehensive statistics display (total tokens, cost, tasks completed, average tokens per task) and consistent error handling.

codeframe/cli/session_commands.py (1)

42-85: LGTM!

The get_session command is well-implemented with:

  • Clean session state display with color-coded status (green for active, yellow otherwise)
  • Friendly handling of 404 (no active session) vs other errors
  • Support for both text and JSON output formats
  • Consistent error handling pattern
codeframe/cli/review_commands.py (5)

43-52: LGTM!

The severity_emoji helper provides good visual indicators for severity levels with appropriate color coding (🔴 critical, 🟠 high, 🟡 medium, 🔵 low, ⚪ info) and a fallback for unknown values.


55-109: LGTM!

The status command correctly implements review status display with:

  • Appropriate color coding for different review states (approved, changes_requested, rejected)
  • Graceful handling of tasks without reviews
  • Clean output showing status, score, and findings count

112-160: LGTM!

The stats command provides a clear overview of project-wide review statistics with appropriate visual indicators (✅ approved, 🔄 changes requested, ❌ rejected) and aggregate metrics.


163-243: LGTM!

The findings command is well-designed with:

  • Optional severity filtering via query parameter
  • Comprehensive summary (total findings, blocking status, severity breakdown)
  • Appropriate truncation of file paths (last 25 chars) and messages (40 chars) for readable table display
  • Clear visual indicators using severity emojis

246-328: LGTM!

The list_reviews command appropriately extends the findings display to project-wide scope with:

  • Task ID column for cross-referencing
  • Adjusted column widths to fit additional information
  • Consistent filtering and display patterns
  • Clear summary and breakdown of findings
codeframe/cli/context_commands.py (4)

43-88: LGTM! Aligns with tiered memory architecture.

The get command correctly displays agent context with tier distribution (HOT/WARM/COLD) using appropriate visual indicators (🔴 🟠 🔵). This aligns with the tiered memory system specified in the coding guidelines.

As per coding guidelines: "Use tiered memory system (HOT/WARM/COLD) with importance scoring."


91-146: LGTM!

The stats command provides detailed tier-level statistics with a clean table format showing item counts and token usage for each tier (hot, warm, cold), supporting effective context management monitoring.


149-180: LGTM! Supports session checkpoint management.

The flash_save command correctly creates context checkpoints, aligning with the session lifecycle management guidelines. Clear success feedback includes checkpoint ID and timestamp for reference.

Based on learnings: "Implement session lifecycle management with auto-save/restore using file-based storage."


183-237: LGTM!

The checkpoints command correctly lists saved context checkpoints with:

  • Clear table display showing checkpoint ID, timestamp, and item count
  • Helpful guidance when no checkpoints exist
  • Clean timestamp formatting (ISO → human-readable)
tests/cli/test_tasks_commands.py (4)

18-65: LGTM!

The list command tests provide good coverage:

  • Success case verifies task titles appear in output
  • Status filter test confirms query parameters are correctly passed to the API
  • Proper mocking of credentials and API responses

67-116: LGTM!

The create command tests appropriately verify:

  • Basic task creation with 201 response handling
  • Optional parameters (priority, description) are correctly included in the JSON payload
  • Success messages appear in output

118-165: LGTM!

The get command tests properly cover:

  • Success case with task details displayed
  • 404 error case with appropriate error message and non-zero exit code

167-189: LGTM!

The update command test verifies the status update operation works correctly with appropriate success messaging.

tests/cli/test_project_commands.py (4)

1-16: LGTM! Well-structured test setup.

The test module follows a clean TDD approach with proper imports and a shared CliRunner instance. The pattern of using tmp_path for credential isolation is appropriate for testing authentication-dependent commands.


18-85: LGTM! Comprehensive list command tests.

Good coverage of success, empty state, and JSON format scenarios. The assertions appropriately verify both exit codes and output content.


87-158: LGTM! Solid create command test coverage.

The tests properly verify success, options passing to API, and conflict handling. The API payload verification in test_create_project_with_options is particularly valuable for ensuring correct data transmission.


160-373: LGTM! Consistent test coverage across all project commands.

The remaining test classes maintain the established patterns. Notable positives:

  • 404 error handling is verified
  • Status filter is tested with API parameter validation
  • Lifecycle commands (start/pause/resume) verify expected output messages
tests/cli/test_review_commands.py (2)

1-16: LGTM! Review command tests follow established patterns.

Consistent with the project commands test module structure, using the same credential mocking and response simulation approach.


18-207: LGTM! Comprehensive review command test coverage.

Good test coverage including:

  • Both existing and missing review states
  • Empty findings scenario with appropriate messaging
  • Security/quality finding categories in the mock data
codeframe/cli/auth.py (2)

1-29: LGTM! Clear module documentation and credential path handling.

The docstring clearly explains the module's responsibilities and security considerations. The get_credentials_path function correctly uses Path.home() for cross-platform compatibility.


59-122: LGTM! Robust token retrieval with proper error handling.

The get_token function correctly:

  • Prioritizes environment variable for CI/CD flexibility
  • Handles missing files, invalid JSON, and read errors gracefully
  • Uses appropriate logging levels (debug for normal flow, warning for errors)

The is_authenticated function provides a clean abstraction.

codeframe/cli/quality_gates_commands.py (2)

41-111: LGTM! Well-implemented quality gates display.

The command provides:

  • Clear status visualization with color coding and emoji
  • Proper handling of empty gates configuration
  • Consistent error handling patterns

This aligns with the coding guidelines for implementing quality gates with multi-stage pre-completion checks.


114-154: LGTM! Clean quality gate trigger implementation.

Good UX with the follow-up command hint (codeframe quality-gates get {task_id}) to check status after triggering.

codeframe/cli/tasks_commands.py (4)

1-43: LGTM! Solid module setup with clear documentation.

The module docstring provides helpful usage examples, and the Typer app is configured correctly with no_args_is_help=True.

Note: require_auth duplication was addressed in the quality_gates_commands.py review.


44-128: LGTM! Well-implemented list command with filtering.

Good attention to detail:

  • Correctly uses priority is not None (line 71) to allow priority 0 filtering
  • Priority emoji labels provide good visual hierarchy
  • Title truncation prevents table overflow

130-179: LGTM! Create command with sensible defaults.

Good defaults for priority (3 = Normal) and status ("pending").


181-280: LGTM! Get and update commands are well-implemented.

The update command correctly:

  • Uses PATCH for partial updates
  • Validates that at least one field is specified before making the API call
  • Uses priority is not None (line 252) to allow setting priority to 0
codeframe/cli/agents_commands.py (4)

1-44: LGTM! Agent management module setup.

Clear documentation with usage examples for all commands. The Typer app is properly configured.


46-148: LGTM! List and assign commands are well-implemented.

Good handling of edge cases:

  • Empty agent list shows helpful guidance
  • 409 conflict provides clear feedback for duplicate assignments
  • Date display is cleanly truncated to YYYY-MM-DD format

150-191: LGTM! Safe remove command with confirmation.

The confirmation prompt provides a safety net, and --force allows scripting. The Exit(0) on cancellation correctly indicates user-initiated abort.


193-287: LGTM! Status and role commands are well-structured.

The status command provides a useful view of agent assignments across projects, and the role command correctly uses PUT for the role update endpoint.

codeframe/cli/auth_commands.py (5)

1-34: LGTM! Well-documented auth module with proper imports.

The module correctly imports from both auth.py (token storage) and api_client.py (API communication).


36-111: LGTM! Login command correctly implements FastAPI Users authentication.

Key implementation details are correct:

  • Uses form-encoded POST with username field (FastAPI Users convention)
  • Password input is hidden via hide_input=True
  • Comprehensive error handling for different HTTP status codes

113-125: LGTM! Simple and effective logout.


127-222: LGTM! Comprehensive register command with auto-login.

Good UX decisions:

  • Password confirmation only when prompting interactively (allows scripting)
  • Auto-login after registration reduces friction
  • Detailed validation error display helps users fix issues

The ALREADY_EXISTS check using string matching (line 193) is reasonable given FastAPI Users' error response format.


224-257: LGTM! Whoami command with good session handling.

The two-step approach (local auth check, then API call) provides better UX:

  • Fails fast if no token exists locally
  • Detects expired/invalid tokens via API response
codeframe/cli/discovery_commands.py (5)

83-165: Progress command implementation looks good.

The progress command properly handles multiple states (idle, discovering, completed), renders a visual progress bar, shows the current question with a panel, and provides helpful next-step hints. Error handling for 404 and authentication is consistent with other commands.


168-226: Answer command implementation is solid.

Properly submits the answer, displays progress updates, handles completion state with PRD generation hint, and provides appropriate error handling for "not active" discovery state. The error parsing on line 217 correctly extracts the detail message.


229-281: Restart command correctly implements confirmation flow.

The --force flag bypasses confirmation appropriately, and the interactive prompt using typer.confirm is well-implemented. Error handling distinguishes between "already completed" (400) and "not found" (404) cases.


284-324: Generate PRD command implementation is correct.

Handles the success case with appropriate messaging and provides clear guidance for error states (discovery not complete, project not found).


46-80: Both codeframe discovery start and codeframe projects start commands do use the same /api/projects/{project_id}/start endpoint (implemented in agents.py). This is intentional per cf-10.2 specification—the single endpoint manages the unified project and discovery lifecycle, checking discovery state to determine whether to initiate discovery or return an already-in-progress status. No separate /api/projects/{project_id}/discovery/start endpoint exists in the discovery router, which only exposes /answer, /progress, /restart, and /generate-prd. The current design is working as specified and does not require changes.

codeframe/cli/checkpoint_commands.py (5)

46-102: List checkpoints implementation is correct.

Properly handles empty list case with helpful guidance, renders table with truncated git commit and date, and uses consistent error handling patterns.


105-149: Create checkpoint correctly builds payload and displays result.

The optional description is conditionally added, and the response is properly formatted with truncated git commit display. The restore hint at the end is helpful.


152-202: Get checkpoint implementation handles metadata well.

The conditional display of cost (line 190-191) and tasks metadata is nicely formatted. Error handling for 404 is appropriate.


245-296: Restore command with preview mode is well-designed.

The dual-mode behavior (preview without --confirm, actual restore with --confirm) is a good UX pattern for destructive operations. The diff preview using Rich Syntax highlighting is appropriate.


299-345: Diff command implementation is correct.

Statistics display is clear with color-coded insertions/deletions, and the diff content is rendered with syntax highlighting.

codeframe/cli/__init__.py (3)

38-165: Top-level commands (init, start, pause, resume, status, chat, config) look correct.

These commands operate on local projects via the Project class and have consistent error handling patterns. The config command properly validates the action argument.


180-259: Serve command is well-implemented with port validation and availability check.

Good use of validate_port_range and check_port_availability before starting. The error messages for common issues (port in use, uvicorn not found) are helpful.


314-328: Sub-app registration is complete and consistent.

All 12 command groups are properly registered with descriptive help text.

tests/cli/test_discovery_commands.py (1)

1-341: Test coverage is comprehensive.

The tests cover:

  • Success paths for all 5 commands
  • Error states (409 conflict, 400 bad request, 404 not found)
  • Interactive confirmation flow (restart without --force)
  • State transitions (idle → discovering → completed)

Good TDD approach as documented.

codeframe/cli/blocker_commands.py (4)

45-112: List blockers implementation is correct with helpful guidance.

The pending blockers hint at line 104 is a nice UX touch. Table formatting with status colors is well done.


115-171: Get blocker with panel display is well-implemented.

Good use of Rich Panel for the question display, and the conditional resolve hint for PENDING status is helpful.


174-210: Resolve command handles edge cases well.

The 409 (already resolved) case provides a clear non-error message with yellow styling, appropriately distinguishing it from true errors while still exiting with code 1.


213-271: Metrics command with time formatting logic is well-designed.

The tiered time formatting (seconds → minutes → hours) on lines 252-257 and the color-coded expiration rate are good UX decisions.

codeframe/cli/api_client.py (4)

29-41: Exception classes are well-designed.

APIError with status_code and detail attributes, and AuthenticationError as a subclass for 401/403, provides good structure for error handling in calling code.


54-74: APIClient initialization is clean.

Good use of defaults with environment variable override for base URL, and automatic token loading from storage when not provided.


102-160: Response handling is comprehensive.

Properly handles 2xx (with JSON parsing fallback), 401/403 with AuthenticationError, 4xx with detail extraction, and 5xx errors. The fallback to response.text when JSON parsing fails is appropriate.


222-279: HTTP method wrappers are clean and consistent.

All methods properly delegate to _request_with_retry with appropriate kwargs.

codeframe/cli/project_commands.py (5)

170-212: Get project implementation is correct.

Properly handles text and JSON formats, displays optional workspace path, and has appropriate 404 handling.


215-260: Status command with progress bar is well-implemented.

The visual progress bar rendering matches the pattern used in discovery_commands.py, maintaining consistency.


263-326: Tasks command with pagination is correct.

Properly passes limit/offset params, displays count information in table title, and handles empty results.


329-370: Activity command implementation is clean.

Timestamp formatting (removing T, truncating to 19 chars) creates readable output.


373-463: Start, pause, resume commands are consistent.

All three follow the same pattern with proper error handling. The optional message display is a nice touch.

Comment thread codeframe/cli/__init__.py Outdated
Comment thread codeframe/cli/project_commands.py
- Remove unused imports (pytest, typing.Any, tempfile, MagicMock)
- Remove f-string prefixes where no placeholders used
- Remove unused last_exception variable in api_client.py
- Add noqa: E402 comments for intentional late imports in __init__.py

All 157 CLI tests continue to pass.
@claude

claude Bot commented Jan 5, 2026

Copy link
Copy Markdown

Comprehensive PR Review: CLI Command Implementation

This is an excellent PR that implements a comprehensive CLI interface with 12 command groups covering all major API endpoints. The implementation follows TDD principles with 157 tests and demonstrates strong software engineering practices. Below are my detailed findings.


Strengths

1. Excellent Architecture & Design

  • Clean separation of concerns: Each command group is in its own module with focused responsibilities
  • Consistent patterns: All command modules follow the same structure (APIClient → require_auth → API call → format output)
  • Rich terminal output: Proper use of Rich library for tables, colors, and formatting
  • Comprehensive test coverage: 157 tests with proper mocking and edge case handling

2. Robust Error Handling

  • APIClient (codeframe/cli/api_client.py:162-216): Excellent retry logic with exponential backoff for transient failures
  • Clear error messages: AuthenticationError provides actionable guidance ("Please log in with: codeframe auth login")
  • Proper exception hierarchy: APIError base class with AuthenticationError subclass

3. Security Best Practices

  • Token storage (codeframe/cli/auth.py:32-57): Credentials stored with 600 permissions (owner read/write only)
  • Environment variable override: Supports CODEFRAME_TOKEN env var for CI/CD scenarios
  • No hardcoded credentials: All auth flows through proper token management

4. Testing Quality

  • Comprehensive mocking: All tests properly isolate from external dependencies
  • Both success and error paths: Tests cover happy paths and failure scenarios
  • Request payload verification: Several tests validate the data sent to API (e.g., test_agents_commands.py:109-110)

🔧 Issues Requiring Fixes

1. CRITICAL: Conflicting checkpoint commands (codeframe/cli/init.py:168-174)

Severity: HIGH
Impact: User confusion, potential runtime conflicts

The stub checkpoint function conflicts with the full checkpoints_app sub-application:

@app.command()
def checkpoint(
    action: str = typer.Argument("create", help="Action: create or list"),
    message: Optional[str] = typer.Option(None, help="Checkpoint message"),
):
    """Manage checkpoints."""
    console.print(f"Checkpoint {action} - [yellow]Not implemented yet[/yellow]")

Problem: Users might invoke codeframe checkpoint (the stub) instead of codeframe checkpoints (the full implementation).

Recommendation: Remove the stub entirely, or convert it to a deprecation notice:

@app.command()
def checkpoint():
    """Deprecated: Use 'codeframe checkpoints' instead."""
    console.print("[yellow]This command is deprecated.[/yellow]")
    console.print("Use: codeframe checkpoints [command]")
    console.print("Example: codeframe checkpoints create --message 'My checkpoint'")
    raise typer.Exit(0)

2. Code Duplication: require_auth helper repeated 8+ times

Severity: MEDIUM
Impact: Maintenance burden, potential inconsistencies

The require_auth function is duplicated across at least 8 modules:

  • codeframe/cli/agents_commands.py:33-38
  • codeframe/cli/metrics_commands.py:33-38
  • codeframe/cli/session_commands.py:33-38
  • codeframe/cli/context_commands.py:33-38
  • codeframe/cli/checkpoint_commands.py:38-43
  • codeframe/cli/discovery_commands.py:38-43
  • codeframe/cli/blocker_commands.py:37-42
  • codeframe/cli/project_commands.py:41-46

Recommendation: Extract to shared utility module:

# codeframe/cli/utils.py
from rich.console import Console
import typer
from codeframe.cli.api_client import APIClient

console = Console()

def require_auth(client: APIClient):
    """Check if client is authenticated, exit with error if not."""
    if not client.token:
        console.print("[yellow]Not logged in.[/yellow]")
        console.print("Please log in: codeframe auth login")
        raise typer.Exit(1)

Then import in each module:

from codeframe.cli.utils import require_auth

3. Unused imports (codeframe/cli/discovery_commands.py:23)

Severity: LOW
Impact: Code cleanliness

from rich.progress import Progress, SpinnerColumn, TextColumn

These are imported but never used. Remove them.


4. Imports at bottom of file (codeframe/cli/init.py:298-312)

Severity: LOW
Impact: Code style, PEP 8 compliance

Command group imports are placed at the bottom after all function definitions. While functional, this violates PEP 8 conventions.

Recommendation: If avoiding circular imports, add a comment explaining why:

# Import command groups at module level to avoid circular imports
# (These modules import from codeframe.cli.api_client which may import from here)
from codeframe.cli.auth_commands import auth_app
# ...

Or restructure to allow top-level imports.


💡 Suggestions for Improvement

1. Browser health check in serve command (codeframe/cli/init.py:232-245)

Current: Fixed 1.5s sleep before opening browser
Issue: May fail on slow machines or under load

Suggestion: Implement health-check loop with timeout:

def open_in_browser():
    import urllib.request
    max_wait = 10  # seconds
    for _ in range(max_wait * 2):
        try:
            urllib.request.urlopen(f"http://localhost:{port}/health", timeout=0.5)
            webbrowser.open(f"http://localhost:{port}")
            return
        except Exception:
            time.sleep(0.5)
    # Fallback: try anyway
    webbrowser.open(f"http://localhost:{port}")

2. Add jitter to exponential backoff (codeframe/cli/api_client.py:197-213)

Current: Pure exponential backoff (1s, 2s, 4s)
Issue: Multiple CLI instances can create synchronized retry storms (thundering herd)

Suggestion: Add random jitter:

import random

if attempt < self.max_retries - 1:
    base_delay = 2 ** attempt
    jitter = random.uniform(0, base_delay * 0.1)
    time.sleep(base_delay + jitter)

3. Test fixture consolidation

Pattern observed: Credentials setup code duplicated across all test files

Suggestion: Create shared pytest fixture in tests/cli/conftest.py:

@pytest.fixture
def mock_credentials(tmp_path):
    """Create mock credentials file and return the path."""
    creds_path = tmp_path / ".codeframe" / "credentials.json"
    creds_path.parent.mkdir(parents=True)
    with open(creds_path, "w") as f:
        json.dump({"access_token": "valid-token"}, f)
    return creds_path

This would reduce duplication across 15+ test files.

4. Inconsistent confirmation flags

  • checkpoint delete uses --force to skip confirmation
  • checkpoint restore uses --confirm to perform action

Suggestion: Standardize on one pattern (preferably --force) for consistency.

5. Redundant authentication hint

In codeframe/cli/project_commands.py:99-102:

except AuthenticationError as e:
    console.print(f"[red]Authentication error:[/red] {e}")
    console.print("Please log in: codeframe auth login")  # Redundant!
    raise typer.Exit(1)

The AuthenticationError message already includes login guidance. Remove line 101.


🔒 Security Review

✅ Secure Practices

  • Token storage with 600 permissions
  • No tokens in logs (debug logs mention "Using token" but don't print the token)
  • Environment variable override for CI/CD
  • No hardcoded secrets

⚠️ Minor: File creation race condition

In codeframe/cli/auth.py:49-54, there's a brief window between file creation and chmod(0o600) where default permissions apply. For a CLI tool, this is acceptable, but for higher-security contexts, consider atomic creation:

import os
fd = os.open(creds_path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
try:
    with os.fdopen(fd, "w") as f:
        json.dump(credentials, f, indent=2)
except:
    os.close(fd)
    raise

📊 Test Coverage Analysis

Strengths

  • 157 tests covering all command groups
  • Success and error paths tested
  • Request payload validation in several tests
  • Proper mocking of API, filesystem, and credentials

Gaps (per CodeRabbit review and issue #172)

  • WebSocket tests accept 0 messages as success
  • Some tests verify DOM exists but not API success
  • No console error monitoring in E2E tests

Note: These are documented in issue #172 and don't block this PR.


📝 Documentation & Code Style

✅ Excellent

  • Comprehensive docstrings on all modules and functions
  • Clear usage examples in command help text
  • Descriptive commit message following conventional commits

Minor improvements

  • Add module-level docstring explaining the CLI structure to new developers
  • Consider adding a docs/cli-development.md guide for adding new command groups

🎯 Recommendations Summary

Must Fix (before merge)

  1. ✅ Remove or deprecate conflicting checkpoint stub command
  2. ✅ Extract require_auth to shared utility module

Should Fix (before merge)

  1. Remove unused imports in discovery_commands.py
  2. Add comment explaining bottom-of-file imports or restructure

Nice to Have (can be follow-up PR)

  1. Add jitter to retry backoff
  2. Implement health-check for browser auto-open
  3. Consolidate test fixtures
  4. Standardize confirmation flag patterns
  5. Remove redundant auth hints

🏆 Final Verdict

APPROVE with requested changes

This is high-quality work that significantly enhances the CLI user experience. The code is well-structured, thoroughly tested, and follows best practices. The issues identified are minor and easily addressable.

Required before merge:

  1. Fix checkpoint command conflict
  2. Extract require_auth to shared utility

Once these two items are addressed, this PR is ready to merge.

Estimated effort to fix: ~15 minutes


Great work on this implementation! The TDD approach and comprehensive test coverage set a strong foundation for future CLI development.

The top-level 'checkpoint' command conflicted with the full
'checkpoints' sub-app. Convert it to a hidden, deprecated shim
that directs users to the proper checkpoints subcommand.
@claude

claude Bot commented Jan 5, 2026

Copy link
Copy Markdown

Code Review Summary

This is an excellent PR that implements a comprehensive CLI interface for CodeFRAME! The implementation demonstrates strong software engineering practices with TDD, extensive test coverage (157 tests), and well-organized code structure. Here's my detailed feedback:

✅ Strengths

  1. Excellent Test Coverage: 157 tests covering all command groups with both success and error paths
  2. Clean Architecture: Well-organized command groups following single responsibility principle
  3. Robust Error Handling: Proper handling of auth errors, API failures, and retry logic with exponential backoff
  4. Security Conscious: Token storage with 600 permissions, environment variable override support
  5. User Experience: Rich terminal output, helpful error messages, JSON output option for scripting
  6. API Client Design: Centralized APIClient with retry logic, timeout handling, and user-friendly error messages

🔍 Issues to Address

1. Code Duplication - require_auth Helper (High Priority)

The require_auth function is duplicated across 11 command modules. This violates DRY principles and makes maintenance harder.

Files affected: agents_commands.py, blocker_commands.py, checkpoint_commands.py, context_commands.py, discovery_commands.py, metrics_commands.py, project_commands.py, quality_gates_commands.py, review_commands.py, session_commands.py, tasks_commands.py

Recommendation: Create a shared utility module:

# codeframe/cli/utils.py
import typer
from rich.console import Console
from codeframe.cli.api_client import APIClient

console = Console()

def require_auth(client: APIClient):
    """Check if client is authenticated, exit with error if not."""
    if not client.token:
        console.print("[yellow]Not logged in.[/yellow]")
        console.print("Please log in: codeframe auth login")
        raise typer.Exit(1)

Then import in each module: from codeframe.cli.utils import require_auth

2. Retry Logic Improvements (Medium Priority)

File: codeframe/cli/api_client.py:197-213

Issues:

  • last_exception is captured but never used in error messages
  • No jitter in exponential backoff (can cause thundering herd in concurrent scenarios)

Recommendations:

import random

# Add jitter to prevent synchronized retries
if attempt < self.max_retries - 1:
    base_delay = 2 ** attempt
    jitter = random.uniform(0, base_delay * 0.1)
    time.sleep(base_delay + jitter)

# Include last exception in final error
raise APIError(
    f"Connection error: Unable to connect to {self.base_url}. "
    f"Last error: {last_exception}",
    status_code=None,
)

3. Inconsistent Flag Semantics (Low Priority)

File: codeframe/cli/checkpoint_commands.py

The delete command uses --force to skip confirmation, while restore uses --confirm to perform the action. This inconsistency may confuse users.

Recommendation: Align flag semantics across commands or clearly document the difference.

4. Import Organization (Low Priority)

File: codeframe/cli/__init__.py:298-319

Command group imports are placed at the bottom after function definitions (with # noqa: E402). While this works, it's unconventional.

Recommendation: Either move imports to the top with a comment explaining deferred loading, or restructure to follow PEP 8 conventions.

5. Unused Imports (Low Priority)

File: codeframe/cli/discovery_commands.py:23

Progress, SpinnerColumn, and TextColumn are imported from rich.progress but never used.

Recommendation: Remove unused imports.

💡 Optional Improvements

Test Fixture for Credentials

The credential file setup is duplicated across all test files. Consider extracting to a shared pytest fixture:

# tests/cli/conftest.py
import pytest
import json

@pytest.fixture
def mock_credentials(tmp_path):
    """Create mock credentials file and return the path."""
    creds_path = tmp_path / ".codeframe" / "credentials.json"
    creds_path.parent.mkdir(parents=True)
    with open(creds_path, "w") as f:
        json.dump({"access_token": "valid-token"}, f)
    return creds_path

Then use in tests: def test_something(self, mock_credentials):

This would reduce hundreds of lines of duplicated setup code across your 157 tests.

Browser Opening Reliability

File: codeframe/cli/__init__.py:242

The hardcoded 1.5s delay before opening browser may be insufficient on slower machines. Consider implementing a health-check loop with timeout.

Atomic Token File Creation

File: codeframe/cli/auth.py:50-54

There's a brief window between file creation and chmod(0o600) where the file has default permissions. For higher security, consider atomic creation with os.open() using the 0o600 mode flag.

🎯 Verdict

LGTM with minor improvements recommended

This is production-ready code with excellent test coverage. The main issue is code duplication of the require_auth helper, which should be refactored before merge. The other issues are minor and can be addressed in follow-up PRs if needed.

The CLI implementation is well-structured, user-friendly, and follows best practices for error handling, security, and testing. Great work!


Recommendation: Merge after addressing the require_auth duplication issue (#1 above). The other improvements can be made in follow-up PRs.

cc: @frankbria

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Fix all issues with AI Agents 🤖
In @codeframe/cli/agents_commands.py:
- Around line 37-42: Extract the duplicated require_auth function into a single
shared helper module (e.g., create codeframe.cli.helpers or codeframe.cli.utils)
containing the Console instance and the require_auth(client: APIClient) function
signature that checks client.token and raises typer.Exit with the same messages;
then replace the local require_auth definitions in discovery_commands.py,
session_commands.py, context_commands.py, tasks_commands.py, blocker_commands.py
and any other command modules with a single import from the new helper module
(import require_auth), removing the duplicated code so all CLI modules use the
same implementation.
- Line 88: The slice agent.get("assigned_at", "")[:10] in agents_commands.py can
fail or produce wrong output for short or malformed strings; add a defensive
check or helper to extract the date safely: implement a small function (e.g.
format_date(date_str: str | None) -> str) that returns "" if date_str is falsy
or shorter than 10, otherwise returns date_str[:10], and replace the inline
slice with a call to format_date(agent.get("assigned_at")). Ensure all uses of
assigned_at in this file use the helper to avoid repeated slicing logic.
- Line 233: The slice of proj.get("assigned_at") is unsafe; before slicing check
its type and length or use the shared format_date helper used elsewhere: replace
the direct slice of proj.get("assigned_at") in agents_commands.py with a call to
format_date(proj.get("assigned_at")) (or ensure proj.get("assigned_at") is a
non-empty string of at least 10 chars before doing proj.get("assigned_at")[:10])
to avoid exceptions when the value is missing or shorter than 10 characters.

In @codeframe/cli/discovery_commands.py:
- Around line 37-42: The require_auth function is duplicated; extract it into a
single shared helper (e.g., a new CLI helper module) and update callers to
import that one function. Move the implementation that checks client.token and
uses console.print + raise typer.Exit into a shared function named
require_auth(client: APIClient), keep the same behavior and signatures, remove
the duplicate implementations from discovery_commands.py and other CLI modules,
and update their imports to use the new shared helper (ensure console, APIClient
and typer are available/imported in the helper).

In @codeframe/cli/review_commands.py:
- Around line 35-41: Extract the duplicated require_auth function into a single
shared helper module (e.g., create codeframe/cli/auth_utils.py) that defines
require_auth(client: APIClient) and the shared Console instance, then update all
command modules that currently define their own require_auth (e.g.,
review_commands.py, tasks_commands.py, discovery_commands.py) to remove the
local function and import require_auth from codeframe.cli.auth_utils; ensure the
signature and behavior remain identical (checking client.token, printing the two
messages, and raising typer.Exit(1)) and that imports reference the APIClient
and typer as needed in the shared module.

In @codeframe/cli/tasks_commands.py:
- Around line 36-41: The require_auth function is duplicated across CLI modules;
extract it into a single shared helper (e.g., a new cli-level module named auth
or utils exposing require_auth) preserving the signature def
require_auth(client: APIClient): and its behavior (console prints and raise
typer.Exit(1)), then update callers (e.g., the require_auth usages in
tasks_commands.py and review_commands.py) to import the shared require_auth
instead of duplicating it; ensure the new module imports console, typer, and
APIClient so callers only need to import the function.
♻️ Duplicate comments (2)
codeframe/cli/project_commands.py (1)

154-156: Misleading message: discovery does not auto-start.

As noted in a previous review, this message incorrectly states "Discovery started automatically" but the backend has no mechanism to auto-start discovery after project creation. The user would need to run codeframe discovery start {project_id} separately.

Either update the message to guide users to start discovery manually, or implement actual auto-start by calling the discovery API after project creation.

codeframe/cli/__init__.py (1)

168-175: Stub checkpoint command conflicts with checkpoints sub-app.

The top-level stub command (codeframe checkpoint) coexists with the full checkpoints sub-app (codeframe checkpoints list, etc.). Consider removing this stub or converting it to a deprecation shim that directs users to use codeframe checkpoints instead.

🧹 Nitpick comments (12)
codeframe/cli/auth_commands.py (2)

147-153: Consider password confirmation for CLI-provided passwords.

When users provide passwords via the --password flag, they skip the confirmation prompt. This could lead to typos being persisted without user awareness. Interactive prompts request confirmation (lines 149-153), but CLI arguments don't.

While this may be intentional for scripting scenarios, consider documenting this behavior or adding an optional --password-confirm flag for safety. Alternatively, always prompt for confirmation when registering, regardless of how the password was provided:

# Prompt for password if not provided
if not password:
    password = typer.prompt("Password", hide_input=True)
    # Confirm password
    password_confirm = typer.prompt("Confirm password", hide_input=True)
    if password != password_confirm:
        console.print("[red]Error:[/red] Passwords don't match")
        raise typer.Exit(1)
else:
    # Password provided via CLI - consider confirming in interactive mode
    if sys.stdin.isatty():  # Only prompt if in interactive terminal
        password_confirm = typer.prompt("Confirm password", hide_input=True)
        if password != password_confirm:
            console.print("[red]Error:[/red] Passwords don't match")
            raise typer.Exit(1)

255-257: Prefer specific exception handling over broad catch.

Catching Exception on Line 255 may hide unexpected errors and make debugging harder. Consider catching specific exceptions like APIError or requests.RequestException.

-    except Exception as e:
-        console.print(f"[red]Error:[/red] {e}")
-        raise typer.Exit(1)
+    except APIError as e:
+        console.print(f"[red]Error:[/red] {e}")
+        raise typer.Exit(1)
+    except Exception as e:
+        # Unexpected error - log for debugging
+        logger.exception("Unexpected error in whoami command")
+        console.print(f"[red]Unexpected error:[/red] {e}")
+        raise typer.Exit(1)
tests/cli/test_quality_gates_commands.py (1)

109-110: Add defensive assertion before accessing mock call arguments.

The test accesses mock_request.call_args.kwargs without first verifying the mock was called. If the command execution fails before making the request, this could raise an AttributeError.

🔎 Suggested improvement
         assert result.exit_code == 0
+        # Verify the API request was made
+        mock_request.assert_called_once()
         call_kwargs = mock_request.call_args.kwargs
         assert call_kwargs["json"].get("gate") == "tests"

This makes the test more explicit about expectations and provides clearer failure messages if the mock wasn't called.

tests/cli/test_agents_commands.py (1)

14-14: Consider using a pytest fixture for the test runner.

While the module-level runner works, using a pytest fixture (as seen in tests/cli/test_cli_session.py lines 18-20) provides better test isolation and is more idiomatic.

🔎 Optional refactor to use fixture
-runner = CliRunner()
+@pytest.fixture
+def runner():
+    """Create CLI test runner."""
+    return CliRunner()

Then update test method signatures to accept runner as a parameter.

tests/cli/test_context_commands.py (2)

14-14: Consider using a pytest fixture for the test runner.

Same as in the agents test file, using a pytest fixture would provide better test isolation.


73-74: Consider more specific assertions for stats output.

The or condition allows the test to pass if only one metric is shown. For a stats command, you may want to assert that both metrics are present in the output.

🔎 More specific assertion
-        assert result.exit_code == 0
-        assert "50" in result.output or "75000" in result.output
+        assert result.exit_code == 0
+        assert "50" in result.output  # total_items
+        assert "75000" in result.output  # total_tokens
tests/cli/test_checkpoint_commands.py (1)

14-14: Consider using a pytest fixture for the test runner.

Consistent with other test files, using a pytest fixture would improve test isolation.

codeframe/cli/blocker_commands.py (1)

37-42: Consolidate duplicated require_auth across CLI modules.

The require_auth function is duplicated across multiple CLI command modules (blocker_commands, metrics_commands, session_commands, context_commands, tasks_commands). This violates the DRY principle and makes maintenance harder.

Consider extracting this to a shared utility module like codeframe/cli/auth_utils.py or including it in the existing codeframe/cli/auth.py module, then importing it where needed.

🔎 Example consolidation

In codeframe/cli/auth.py, add:

def require_auth(client: APIClient):
    """Check if client is authenticated, exit with error if not."""
    if not client.token:
        console.print("[yellow]Not logged in.[/yellow]")
        console.print("Please log in: codeframe auth login")
        raise typer.Exit(1)

Then in command modules:

-def require_auth(client: APIClient):
-    """Check if client is authenticated, exit with error if not."""
-    if not client.token:
-        console.print("[yellow]Not logged in.[/yellow]")
-        console.print("Please log in: codeframe auth login")
-        raise typer.Exit(1)
+from codeframe.cli.auth import require_auth
codeframe/cli/metrics_commands.py (1)

33-38: Consolidate duplicated require_auth across CLI modules.

Same duplication issue as in blocker_commands.py. The require_auth function appears in multiple CLI modules and should be consolidated into a shared utility.

Refer to the consolidation approach suggested in the blocker_commands review.

codeframe/cli/review_commands.py (1)

58-58: Consider standardizing the default output format across commands.

Within this module, status and stats commands default to "text" format, while findings and list_reviews default to "table" format. This inconsistency may confuse users about what to expect from different commands.

Consider either:

  • Defaulting all to "table" for consistency (since findings naturally fit tables)
  • Or document why certain commands use different defaults

Also applies to: 115-115, 167-167, 250-250

codeframe/cli/tasks_commands.py (1)

135-135: Add validation for priority values.

The help text indicates priority should be 0-4 (0=critical, 4=low), but there's no validation to enforce this range. Users could pass invalid values like -1 or 10, which would be sent to the API.

🔎 Proposed validation

Add validation in both create and update commands:

 @tasks_app.command()
 def create(
     project_id: int = typer.Argument(..., help="Project ID"),
     title: str = typer.Argument(..., help="Task title"),
     description: Optional[str] = typer.Option(None, "--description", "-d", help="Task description"),
     priority: int = typer.Option(3, "--priority", "-p", help="Priority (0=critical, 4=low)"),
     status: str = typer.Option("pending", "--status", "-s", help="Initial status"),
 ):
     """Create a new task."""
     try:
         client = APIClient()
         require_auth(client)
+
+        if not 0 <= priority <= 4:
+            console.print("[red]Error:[/red] Priority must be between 0 and 4")
+            raise typer.Exit(1)

         data = {
             "project_id": project_id,

Similar validation in update command around line 252.

Also applies to: 231-231

codeframe/cli/context_commands.py (1)

35-41: Consider extracting require_auth to a shared utility.

This helper is duplicated across multiple CLI modules (context_commands, checkpoint_commands, project_commands, etc.). Extracting it to a common location (e.g., api_client.py or a new cli_utils.py) would reduce duplication.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dab798e and bad651e.

📒 Files selected for processing (27)
  • codeframe/cli/__init__.py
  • codeframe/cli/agents_commands.py
  • codeframe/cli/api_client.py
  • codeframe/cli/auth_commands.py
  • codeframe/cli/blocker_commands.py
  • codeframe/cli/checkpoint_commands.py
  • codeframe/cli/context_commands.py
  • codeframe/cli/discovery_commands.py
  • codeframe/cli/metrics_commands.py
  • codeframe/cli/project_commands.py
  • codeframe/cli/quality_gates_commands.py
  • codeframe/cli/review_commands.py
  • codeframe/cli/tasks_commands.py
  • tests/cli/test_agents_commands.py
  • tests/cli/test_api_client.py
  • tests/cli/test_auth_commands.py
  • tests/cli/test_auth_module.py
  • tests/cli/test_blocker_commands.py
  • tests/cli/test_checkpoint_commands.py
  • tests/cli/test_context_commands.py
  • tests/cli/test_discovery_commands.py
  • tests/cli/test_metrics_commands.py
  • tests/cli/test_project_commands.py
  • tests/cli/test_quality_gates_commands.py
  • tests/cli/test_review_commands.py
  • tests/cli/test_session_commands.py
  • tests/cli/test_tasks_commands.py
🚧 Files skipped from review as they are similar to previous changes (7)
  • tests/cli/test_review_commands.py
  • tests/cli/test_discovery_commands.py
  • tests/cli/test_api_client.py
  • tests/cli/test_session_commands.py
  • tests/cli/test_tasks_commands.py
  • tests/cli/test_metrics_commands.py
  • codeframe/cli/quality_gates_commands.py
🧰 Additional context used
📓 Path-based instructions (1)
codeframe/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

codeframe/**/*.py: Use Python 3.11+ for backend development with FastAPI, AsyncAnthropic, SQLite with async support (aiosqlite), and tiktoken for token counting
Use token counting via tiktoken library for token budget management with ~50,000 token limit per conversation
Use asyncio patterns with AsyncAnthropic for async/await in Python backend for concurrent operations
Implement quality gates with multi-stage pre-completion checks (tests → type → coverage → review) and Git + SQLite + context snapshots for project state rollback
Use tiered memory system (HOT/WARM/COLD) with importance scoring using hybrid exponential decay algorithm for context management with 30-50% token reduction
Implement session lifecycle management with auto-save/restore using file-based storage at .codeframe/session_state.json

Files:

  • codeframe/cli/api_client.py
  • codeframe/cli/checkpoint_commands.py
  • codeframe/cli/review_commands.py
  • codeframe/cli/tasks_commands.py
  • codeframe/cli/blocker_commands.py
  • codeframe/cli/context_commands.py
  • codeframe/cli/discovery_commands.py
  • codeframe/cli/metrics_commands.py
  • codeframe/cli/agents_commands.py
  • codeframe/cli/__init__.py
  • codeframe/cli/auth_commands.py
  • codeframe/cli/project_commands.py
🧠 Learnings (4)
📚 Learning: 2026-01-04T06:26:12.870Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T06:26:12.870Z
Learning: Applies to codeframe/**/*.py : Implement quality gates with multi-stage pre-completion checks (tests → type → coverage → review) and Git + SQLite + context snapshots for project state rollback

Applied to files:

  • tests/cli/test_quality_gates_commands.py
  • tests/cli/test_project_commands.py
📚 Learning: 2026-01-04T06:26:12.870Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T06:26:12.870Z
Learning: Applies to codeframe/auth/**/*.py : Organize Python backend files with Auth module at codeframe/auth/ containing dependencies.py (get_current_user), manager.py (UserManager), models.py, router.py, and schemas.py

Applied to files:

  • tests/cli/test_auth_module.py
  • codeframe/cli/auth_commands.py
📚 Learning: 2026-01-04T06:26:12.870Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T06:26:12.870Z
Learning: Applies to codeframe/auth/**/*.py : For authentication, use FastAPI Users with JWT tokens and mandatory authentication (no bypass mode)

Applied to files:

  • codeframe/cli/auth_commands.py
📚 Learning: 2026-01-04T06:26:12.870Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T06:26:12.870Z
Learning: Applies to web-ui/src/app/page.tsx : Implement automatic project discovery start after project creation with loading state transitions and 'Start Discovery' button for idle projects

Applied to files:

  • codeframe/cli/project_commands.py
🧬 Code graph analysis (14)
tests/cli/test_quality_gates_commands.py (3)
codeframe/cli/api_client.py (1)
  • get (218-228)
tests/cli/test_cli_session.py (1)
  • runner (19-21)
codeframe/cli/quality_gates_commands.py (1)
  • get (42-111)
codeframe/cli/tasks_commands.py (1)
codeframe/cli/api_client.py (5)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • get (218-228)
  • post (230-240)
  • patch (254-264)
codeframe/cli/blocker_commands.py (5)
codeframe/cli/api_client.py (3)
  • APIClient (54-275)
  • APIError (29-35)
  • AuthenticationError (38-41)
codeframe/cli/context_commands.py (1)
  • require_auth (35-40)
codeframe/cli/metrics_commands.py (1)
  • require_auth (33-38)
codeframe/cli/tasks_commands.py (1)
  • require_auth (36-41)
codeframe/cli/session_commands.py (1)
  • require_auth (34-39)
codeframe/cli/context_commands.py (1)
codeframe/cli/api_client.py (5)
  • APIClient (54-275)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • get (218-228)
  • post (230-240)
codeframe/cli/discovery_commands.py (1)
codeframe/cli/api_client.py (4)
  • APIClient (54-275)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • get (218-228)
tests/cli/test_project_commands.py (2)
codeframe/cli/api_client.py (2)
  • patch (254-264)
  • get (218-228)
codeframe/cli/project_commands.py (1)
  • get (171-212)
tests/cli/test_checkpoint_commands.py (2)
codeframe/cli/api_client.py (1)
  • patch (254-264)
tests/cli/test_cli_session.py (1)
  • runner (19-21)
codeframe/cli/metrics_commands.py (1)
codeframe/cli/api_client.py (3)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • get (218-228)
tests/cli/test_auth_module.py (1)
codeframe/cli/auth.py (5)
  • get_credentials_path (23-29)
  • store_token (32-56)
  • get_token (59-99)
  • clear_token (102-113)
  • is_authenticated (116-122)
codeframe/cli/agents_commands.py (7)
tests/api/conftest.py (1)
  • api_client (67-177)
codeframe/cli/api_client.py (7)
  • APIClient (54-275)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • get (218-228)
  • post (230-240)
  • delete (266-275)
  • put (242-252)
codeframe/cli/blocker_commands.py (2)
  • require_auth (37-42)
  • get (116-171)
codeframe/cli/context_commands.py (2)
  • require_auth (35-40)
  • get (44-88)
codeframe/cli/discovery_commands.py (1)
  • require_auth (37-42)
codeframe/cli/tasks_commands.py (2)
  • require_auth (36-41)
  • get (182-224)
codeframe/cli/session_commands.py (1)
  • require_auth (34-39)
tests/cli/test_blocker_commands.py (2)
codeframe/cli/api_client.py (2)
  • patch (254-264)
  • get (218-228)
codeframe/cli/blocker_commands.py (1)
  • get (116-171)
codeframe/cli/auth_commands.py (2)
codeframe/cli/auth.py (3)
  • store_token (32-56)
  • clear_token (102-113)
  • is_authenticated (116-122)
codeframe/cli/api_client.py (5)
  • APIClient (54-275)
  • AuthenticationError (38-41)
  • get_api_base_url (44-51)
  • post (230-240)
  • get (218-228)
tests/cli/test_auth_commands.py (3)
codeframe/cli/api_client.py (1)
  • patch (254-264)
tests/cli/test_cli_session.py (1)
  • runner (19-21)
codeframe/core/config.py (1)
  • load (223-235)
tests/cli/test_agents_commands.py (3)
codeframe/cli/api_client.py (1)
  • patch (254-264)
tests/cli/test_cli_session.py (1)
  • runner (19-21)
tests/cli/test_project_commands.py (1)
  • test_status_success (211-238)
⏰ 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: Frontend Unit Tests
  • GitHub Check: Backend Unit Tests
  • GitHub Check: claude-review
  • GitHub Check: E2E Smoke Tests (Chromium)
🔇 Additional comments (46)
tests/cli/test_auth_commands.py (1)

1-222: LGTM! Comprehensive test coverage.

The test suite is well-structured with:

  • Clear test organization into logical classes
  • Good coverage of success and error paths
  • Proper mocking of external dependencies (requests, filesystem)
  • Validation of both CLI output and side effects (token storage)
  • Edge case testing (prompts, expired tokens, non-existent users)

The TDD approach is evident and the tests provide good confidence in the auth commands implementation.

tests/cli/test_auth_module.py (1)

1-226: LGTM! Excellent test coverage for auth module.

This test suite thoroughly validates the auth module's core functionality:

  • ✅ Credential path resolution and structure
  • ✅ Token storage with secure permissions (600)
  • ✅ Token retrieval with proper precedence (env var → file)
  • ✅ Robust error handling (invalid JSON, missing keys, I/O errors)
  • ✅ Token clearing operations
  • ✅ Authentication state detection

The tests are well-organized, use appropriate mocking/patching, and cover edge cases comprehensively. This provides strong confidence in the authentication infrastructure.

codeframe/cli/blocker_commands.py (3)

45-113: LGTM - Well-structured list command.

The list_blockers command has good error handling, supports filtering and multiple output formats, and provides helpful guidance when pending blockers are found.


115-211: LGTM - Robust blocker resolution flow.

Both get and resolve commands handle errors appropriately (404, 409 conflict) and provide clear user feedback with colored status indicators and guidance messages.


213-271: LGTM - Well-designed metrics display.

The metrics command provides clear visualization with smart time formatting and threshold-based color coding for the expiration rate.

codeframe/cli/metrics_commands.py (3)

46-106: LGTM - Clear token metrics display.

The tokens command provides comprehensive token usage information with proper formatting and per-agent breakdown.


108-167: LGTM - Well-formatted cost metrics.

The costs command displays cost information clearly with proper currency formatting and a reasonable 7-day breakdown.


170-215: LGTM - Comprehensive agent metrics.

The agent command provides useful per-agent statistics with consistent formatting and error handling.

codeframe/cli/review_commands.py (2)

228-228: Path truncation approach is acceptable but could be misleading.

Using string slicing (e.g., [-25:]) to truncate file paths takes the last N characters, which could be confusing when multiple files share similar endings (e.g., src/foo/utils.py and lib/bar/utils.py both display as .../bar/utils.py).

This is acceptable for display purposes in a terminal table with space constraints, but be aware that identical truncated paths might appear for different files.

Also applies to: 313-313


43-52: Well-structured CLI commands with comprehensive error handling.

The command implementations follow a consistent pattern with:

  • Clear authentication checks
  • Proper error handling for different HTTP status codes
  • Support for both JSON and formatted text output
  • User-friendly messaging and next-step guidance

The severity emoji mapping and Rich-based formatting enhance the user experience.

Also applies to: 55-328

tests/cli/test_blocker_commands.py (1)

1-230: Comprehensive test coverage for blocker CLI commands.

The test suite follows solid testing practices:

  • Proper isolation using tmp_path for credentials
  • Appropriate mocking of HTTP layer via requests.request
  • Coverage of both success and error scenarios (404, 409, etc.)
  • Verification of API parameter passing (e.g., status filter on line 82)
  • Exit code and output assertions

The TDD approach aligns with the PR objectives.

tests/cli/test_project_commands.py (1)

1-372: Excellent test coverage for project CLI commands.

The test suite is comprehensive and well-structured:

  • Tests all lifecycle commands (create, get, list, status, tasks, activity, start, pause, resume)
  • Validates API payload structure (lines 134-137) to ensure correct data is sent
  • Tests query parameter passing for filters (lines 282, 287)
  • Covers error scenarios with appropriate HTTP status codes
  • Verifies both table and JSON output formats
  • Follows consistent mocking patterns for isolation
codeframe/cli/tasks_commands.py (1)

44-127: Well-implemented task management commands.

The commands provide comprehensive task management functionality:

  • Flexible filtering by status and priority
  • Clear priority visualization with emoji indicators (lines 105-107)
  • Support for both table and JSON output formats
  • Helpful error messages and next-step guidance
  • Proper handling of optional fields in create/update operations
  • Validation that at least one field is specified for updates (lines 257-260)

Also applies to: 130-280

codeframe/cli/discovery_commands.py (1)

45-323: Excellent discovery workflow implementation with great UX.

The discovery commands provide a well-thought-out workflow:

  • Clear state management (idle, discovering, completed)
  • Visual progress bar rendering (lines 132-135) enhances user experience
  • Contextual error messages that guide users to correct actions
  • Confirmation prompt for destructive operations (restart, lines 249-255)
  • Helpful next-step suggestions throughout the workflow
  • Proper handling of edge cases (already in progress, not started, completed)

The implementation provides good guardrails for the multi-step discovery process.

codeframe/cli/context_commands.py (5)

1-33: LGTM!

Module setup follows consistent patterns with other CLI modules. The Typer app configuration and Rich console initialization are correct.


43-88: LGTM!

The get command is well-structured with proper error handling, user-friendly output formatting with emoji tier indicators, and support for both text and JSON output formats.


91-146: LGTM!

The stats command properly displays context statistics with a well-formatted Rich table for tier breakdown.


149-180: LGTM!

The flash_save command correctly creates context checkpoints with appropriate success messaging and error handling.


183-237: LGTM!

The checkpoints command properly lists context checkpoints with a nicely formatted table. The timestamp formatting is handled well for display purposes.

codeframe/cli/api_client.py (7)

1-26: LGTM!

Module documentation clearly explains the purpose and usage. Imports are appropriate for the HTTP client functionality.


29-41: LGTM!

Exception hierarchy is well-designed. AuthenticationError as a subclass of APIError allows callers to catch authentication failures specifically or handle all API errors generically.


44-51: LGTM!

The get_api_base_url function correctly handles environment variable lookup with a sensible default and proper URL normalization.


54-87: LGTM!

The APIClient initialization properly handles optional parameters with sensible defaults. The header construction correctly adds the Authorization header only when a token is present.


89-160: LGTM!

URL construction and response handling are comprehensive. The response handler correctly distinguishes between success, authentication errors, client errors, and server errors with appropriate exception types and user-friendly messages.


162-216: LGTM!

The retry logic with exponential backoff is correctly implemented. The handling of ConnectionError and Timeout with appropriate retry behavior and final error reporting is well done.


218-275: LGTM!

HTTP method wrappers provide a clean, consistent API. The use of json=data parameter correctly handles JSON serialization for request bodies.

codeframe/cli/checkpoint_commands.py (7)

1-44: LGTM!

Module setup follows established patterns. The Syntax import from Rich is appropriate for the diff display functionality.


46-103: LGTM!

The list_checkpoints command properly handles both populated and empty checkpoint lists with appropriate formatting and user guidance.


105-149: LGTM!

The create command is well-implemented with helpful post-creation guidance showing how to restore to the new checkpoint.


152-202: LGTM!

The get command properly displays checkpoint details with well-formatted metadata including task completion and cost information.


205-242: LGTM!

The delete command implements proper safety measures with confirmation prompts and a --force flag for scripted usage.


245-296: LGTM!

The restore command implements an excellent two-phase workflow: preview changes first, then confirm to execute. The diff preview with syntax highlighting provides a clear view of what will change.


299-345: LGTM!

The diff command provides clear statistics and well-formatted diff output with appropriate color coding for additions and deletions.

codeframe/cli/project_commands.py (7)

1-47: LGTM!

Module setup follows consistent patterns with other CLI modules.


49-106: LGTM!

The list_projects command properly handles both populated and empty project lists with clear formatting.


170-212: LGTM!

The get command properly displays project details with appropriate formatting and error handling.


215-260: LGTM!

The status command provides a clear visual representation of project progress with a text-based progress bar.


263-326: LGTM!

The tasks command properly implements filtering and pagination with a well-formatted table output.


329-370: LGTM!

The activity command properly displays recent project activities with clear timestamp formatting.


373-463: LGTM!

The lifecycle commands (start, pause, resume) are consistently implemented with appropriate success messaging and error handling.

codeframe/cli/__init__.py (6)

1-31: LGTM!

Module setup correctly configures the main Typer application with appropriate imports for the CLI functionality.


38-115: LGTM!

Legacy commands for local project operations are correctly implemented. The coexistence with API-based project commands under codeframe projects provides backward compatibility while adding new API functionality.


180-259: LGTM!

The serve command is well-implemented with proper port validation, browser auto-launch, and comprehensive error handling. The background thread for browser opening prevents blocking the server startup.


262-289: LGTM!

The clear-session and version commands are simple and correctly implemented.


292-329: LGTM!

Command group imports and registrations are correctly organized. The Phase 1/Phase 2 separation provides clear documentation of the CLI evolution. All 12 command groups are properly registered with descriptive help text.


332-333: LGTM!

Standard CLI entry point pattern.

Comment thread codeframe/cli/agents_commands.py Outdated
Comment thread codeframe/cli/agents_commands.py Outdated
Comment thread codeframe/cli/agents_commands.py Outdated
Comment thread codeframe/cli/discovery_commands.py Outdated
Comment thread codeframe/cli/review_commands.py Outdated
Comment thread codeframe/cli/tasks_commands.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 @codeframe/cli/__init__.py:
- Around line 98-116: The status command is using wrong dict keys from
Project.get_status(); update the status() function to access status['name']
instead of status['project_name'] and status['progress_pct'] instead of
status['completion_percentage'] (i.e., change the two console.print calls that
reference project_name and completion_percentage to use name and progress_pct
respectively) so the printed values match the keys returned by
Project.get_status().
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bad651e and 52788fc.

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

📄 CodeRabbit inference engine (CLAUDE.md)

codeframe/**/*.py: Use Python 3.11+ for backend development with FastAPI, AsyncAnthropic, SQLite with async support (aiosqlite), and tiktoken for token counting
Use token counting via tiktoken library for token budget management with ~50,000 token limit per conversation
Use asyncio patterns with AsyncAnthropic for async/await in Python backend for concurrent operations
Implement quality gates with multi-stage pre-completion checks (tests → type → coverage → review) and Git + SQLite + context snapshots for project state rollback
Use tiered memory system (HOT/WARM/COLD) with importance scoring using hybrid exponential decay algorithm for context management with 30-50% token reduction
Implement session lifecycle management with auto-save/restore using file-based storage at .codeframe/session_state.json

Files:

  • codeframe/cli/__init__.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-11-25T19:08:37.203Z
Learning: Use feature branches from main with Conventional Commits format (feat/fix/docs scope): description
🧬 Code graph analysis (1)
codeframe/cli/__init__.py (9)
codeframe/core/port_utils.py (2)
  • check_port_availability (26-65)
  • validate_port_range (68-88)
codeframe/cli/project_commands.py (6)
  • create (110-167)
  • start (374-401)
  • pause (405-432)
  • resume (436-463)
  • status (216-260)
  • get (171-212)
codeframe/cli/discovery_commands.py (1)
  • start (46-79)
codeframe/cli/agents_commands.py (1)
  • status (193-247)
codeframe/cli/review_commands.py (1)
  • status (56-109)
codeframe/core/project.py (1)
  • get_status (445-613)
codeframe/cli/blocker_commands.py (1)
  • get (116-171)
codeframe/cli/context_commands.py (1)
  • get (44-88)
codeframe/core/session_manager.py (1)
  • SessionManager (9-91)
⏰ 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). (2)
  • GitHub Check: Backend Unit Tests
  • GitHub Check: E2E Smoke Tests (Chromium)
🔇 Additional comments (9)
codeframe/cli/__init__.py (9)

1-30: LGTM! Clean module setup and imports.

The module docstring clearly describes the CLI structure, imports are well-organized, and the Typer app is properly configured.


38-54: LGTM! Well-structured init command with helpful user guidance.

The command properly creates a project and provides clear next steps for users.


56-96: LGTM! Consistent command implementations.

The start, pause, and resume commands follow a clear, consistent pattern with appropriate error handling.


118-166: LGTM! Chat and config commands are well-implemented.

Both commands have clear logic, appropriate input validation, and helpful error messages.


168-180: Excellent resolution of the checkpoint conflict!

The deprecated checkpoint command is now properly marked as hidden=True and provides clear guidance to users about the new checkpoints subcommand. This effectively addresses the previous review comment about the naming conflict.


185-265: LGTM! Robust serve command with comprehensive validation.

The command properly validates the port range and availability before starting the server, handles errors gracefully with actionable messages, and safely opens the browser in a background thread. The pre-flight checks and error handling follow best practices.


267-287: LGTM! Clear and straightforward session clearing.

The command properly uses the SessionManager to clear session state with appropriate error handling.


289-295: LGTM! Simple version display.

The version command is concise and properly formatted.


297-335: LGTM! Well-organized command group registration.

The imports and registrations are cleanly structured with appropriate E402 suppression (since imports must follow app definition). All 12 command groups are properly registered with descriptive help text.

Comment thread codeframe/cli/__init__.py
- Create helpers.py with shared console, require_auth(), and format_date()
- Remove duplicated require_auth from all 12 command modules
- Replace unsafe date slicing with format_date() helper
- Fix status command to use correct dict keys (name, progress_pct)
- All 157 tests continue to pass, ruff checks clean
@claude

claude Bot commented Jan 5, 2026

Copy link
Copy Markdown

Code Review - PR #190: feat(cli): Add comprehensive CLI command groups for API coverage

I've reviewed this PR and overall it's well-structured with good test coverage (157 tests). Here's my detailed feedback:

✅ Strengths

  1. Excellent Architecture: Clean separation of concerns with modular command groups
  2. Comprehensive Test Coverage: 157 tests covering all major workflows
  3. Good Documentation: Clear docstrings and usage examples in command help text
  4. Robust Error Handling: Proper authentication checks and user-friendly error messages
  5. Retry Logic: Exponential backoff in APIClient for transient failures
  6. Security Conscious: Token storage with 600 permissions, environment variable override support

🔍 Code Quality Observations

1. APIClient Retry Logic (codeframe/cli/api_client.py)

The retry logic only catches ConnectionError and Timeout exceptions but re-raises other exceptions immediately. Consider whether HTTP 5xx errors should also be retried:

Current behavior: 5xx errors fail immediately
Recommendation: Consider retrying 5xx errors (with backoff) as they're often transient

# Line 193 - Consider adding retry for 5xx errors
except requests.ConnectionError as e:
    # ... retry logic
except requests.Timeout as e:
    # ... retry logic
# Missing: except APIError as e if e.status_code >= 500

2. Token Storage Security (codeframe/cli/auth.py)

Token storage is good with 600 permissions, but there's a potential race condition:

Issue: File is written before permissions are set (lines 50-54)
Risk: Brief window where file has default permissions
Recommendation: Use os.open() with explicit mode or tempfile + atomic rename

# Current (line 50-54):
with open(creds_path, 'w') as f:
    json.dump(credentials, f, indent=2)
creds_path.chmod(0o600)  # Race condition here

# Better approach:
fd = os.open(creds_path, os.O_CREAT | os.O_WRONLY | os.O_TRUNC, 0o600)
with os.fdopen(fd, 'w') as f:
    json.dump(credentials, f, indent=2)

3. Import Organization (codeframe/cli/__init__.py)

Intentional E402 (imports after code) with comment - this is fine, but consider alternative:

Current: Main app defined, then command groups imported (lines 295-320)
Alternative: Use TYPE_CHECKING or lazy loading to avoid circular imports while keeping imports at top

4. Deprecated Command Handling (codeframe/cli/__init__.py:166)

The checkpoint command is marked deprecated but still accepts arguments that are ignored:

@app.command(deprecated=True, hidden=True)
def checkpoint(
    action: str = typer.Argument("create", help="Action: create or list"),
    message: Optional[str] = typer.Option(None, help="Checkpoint message"),
):

Recommendation: Either remove arguments entirely or redirect them to new command

5. Date Formatting (codeframe/cli/helpers.py:36)

The format_date function silently returns empty string for invalid inputs:

def format_date(date_str: str | None, length: int = 10) -> str:
    if not date_str or len(date_str) < length:
        return ""  # Silent failure
    return date_str[:length]

Issue: No validation that it's actually a date string
Recommendation: Consider using datetime.fromisoformat() for validation, or document that this is intentionally lenient

6. Port Validation (codeframe/cli/__init__.py:202-210)

The serve command validates ports but references validate_port_range and check_port_availability from codeframe.core.port_utils:

Concern: Are these utilities tested? Should be verified they exist and work correctly.

🔒 Security Considerations

  1. Token Exposure in Logs: Logger uses debug level for token operations (good)
  2. Environment Variable Override: CODEFRAME_TOKEN takes precedence - document this security implication
  3. File Permissions: 600 on credentials file is correct
  4. Token in Memory: Tokens stored in memory during execution (acceptable for CLI)

🧪 Testing Gaps

Based on the PR description, manual verification is still pending:

- [x] All 157 CLI tests pass
- [x] CLI imports successfully
- [x] Help output shows all 12 command groups
- [ ] Manual verification of key workflows  # ⚠️ Still pending

Recommendation: Add at least one E2E test for a complete workflow (login → create project → assign agent)

📝 Documentation

  1. Module docstrings: Excellent, clear usage examples
  2. Command help text: Comprehensive with examples
  3. Missing: No CHANGELOG entry or migration guide for users

🎯 Recommendations Summary

High Priority:

  • Fix token file permission race condition (security)
  • Complete manual testing of key workflows

Medium Priority:

  • Add retry logic for 5xx server errors
  • Add E2E workflow test
  • Validate port_utils module exists and is tested

Low Priority:

  • Improve date formatting with validation
  • Add CHANGELOG entry
  • Consider deprecating unused checkpoint command arguments

✅ Approval Status

Recommendation: Approve with minor fixes suggested

This is solid work with good architecture and test coverage. The security issue with token file permissions should be addressed before merge, but otherwise this is ready to go. The codebase follows project conventions from CLAUDE.md well.


Estimated Review Complexity: 4/5 (Complex) - Multiple command groups, API client, auth system
Test Coverage: 157 tests ✅
Security: Generally good with one fixable issue
Documentation: Excellent docstrings and examples

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 @codeframe/cli/checkpoint_commands.py:
- Line 129: The console.print call uses result.get('git_commit', '')[:7] which
can raise TypeError when git_commit is None; change to use the safe pattern
(e.g., (result.get('git_commit') or '')[:7]) where this print occurs so None
falls back to empty string—update the expression in the checkpoint display code
that constructs the Commit string (the console.print line referencing result and
'git_commit').
♻️ Duplicate comments (3)
codeframe/cli/review_commands.py (1)

1-319: LGTM! Successfully uses shared helpers.

The module now correctly imports require_auth and console from the shared helpers module, eliminating the duplication that was previously flagged in review comments. All commands consistently use require_auth(client) and have comprehensive error handling.

Based on learnings, this resolves the code duplication concern raised in the past review comment for this file.

codeframe/cli/agents_commands.py (1)

1-277: LGTM! Successfully addresses unsafe date slicing with shared helper.

The module now correctly uses format_date() from the shared helpers module (lines 79, 224), replacing the previously unsafe [:10] slicing that was flagged in past review comments. This defensive approach handles None values and short strings gracefully.

All commands demonstrate good practices:

  • Consistent authentication enforcement
  • Interactive confirmations where appropriate (remove command)
  • Multiple output formats (table/json)
  • Specific error handling for different scenarios (404, 409)

Based on learnings, this resolves the unsafe date slicing concerns raised in past review comments for this file at lines 88 and 233.

codeframe/cli/project_commands.py (1)

145-148: The --no-discovery message is misleading.

The message at lines 145-147 states "Discovery started automatically" when --no-discovery is False. However, based on the past review analysis, discovery does not actually auto-start after project creation—it requires a separate codeframe discovery start command. This misleads users into thinking discovery has begun.

Either implement auto-start by making an additional API call, or correct the message:

Proposed fix if auto-start is not intended
         if not no_discovery:
-            console.print("\n[cyan]Discovery started automatically.[/cyan]")
-            console.print(f"Check progress: codeframe discovery progress {result.get('id')}")
+            console.print(f"\n[cyan]Start discovery:[/cyan] codeframe discovery start {result.get('id')}")
🧹 Nitpick comments (2)
codeframe/cli/auth_commands.py (1)

172-188: Consider logging auto-login failures for better diagnostics.

The auto-login after registration silently swallows errors and only suggests manual login. While functional, logging the failure reason could help users troubleshoot issues.

🔎 Optional enhancement
             if login_response.status_code == 200:
                 token = login_response.json().get("access_token")
                 if token:
                     store_token(token)
                     console.print("[green]✓ Logged in automatically[/green]")
             else:
-                console.print("[yellow]Note:[/yellow] Please log in manually: codeframe auth login")
+                console.print(
+                    f"[yellow]Note:[/yellow] Auto-login failed (HTTP {login_response.status_code}). "
+                    "Please log in manually: codeframe auth login"
+                )
codeframe/cli/project_commands.py (1)

346-354: Consider using format_date from helpers for consistent formatting.

The commit message mentions format_date() was added to helpers.py to replace unsafe date slicing. While this slicing is safe (it handles empty strings), using the shared helper would ensure consistency across the CLI.

Proposed refactor
+from codeframe.cli.helpers import console, require_auth, format_date
 ...
         for item in activities:
-            timestamp = item.get("timestamp", "")[:19].replace("T", " ")
+            timestamp = format_date(item.get("timestamp", ""))
             action = item.get("action", "unknown")
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 52788fc and 23d2464.

📒 Files selected for processing (14)
  • codeframe/cli/__init__.py
  • codeframe/cli/agents_commands.py
  • codeframe/cli/auth_commands.py
  • codeframe/cli/blocker_commands.py
  • codeframe/cli/checkpoint_commands.py
  • codeframe/cli/context_commands.py
  • codeframe/cli/discovery_commands.py
  • codeframe/cli/helpers.py
  • codeframe/cli/metrics_commands.py
  • codeframe/cli/project_commands.py
  • codeframe/cli/quality_gates_commands.py
  • codeframe/cli/review_commands.py
  • codeframe/cli/session_commands.py
  • codeframe/cli/tasks_commands.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • codeframe/cli/metrics_commands.py
  • codeframe/cli/context_commands.py
  • codeframe/cli/blocker_commands.py
  • codeframe/cli/tasks_commands.py
  • codeframe/cli/session_commands.py
🧰 Additional context used
📓 Path-based instructions (1)
codeframe/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

codeframe/**/*.py: Use Python 3.11+ for backend development with FastAPI, AsyncAnthropic, SQLite with async support (aiosqlite), and tiktoken for token counting
Use token counting via tiktoken library for token budget management with ~50,000 token limit per conversation
Use asyncio patterns with AsyncAnthropic for async/await in Python backend for concurrent operations
Implement quality gates with multi-stage pre-completion checks (tests → type → coverage → review) and Git + SQLite + context snapshots for project state rollback
Use tiered memory system (HOT/WARM/COLD) with importance scoring using hybrid exponential decay algorithm for context management with 30-50% token reduction
Implement session lifecycle management with auto-save/restore using file-based storage at .codeframe/session_state.json

Files:

  • codeframe/cli/__init__.py
  • codeframe/cli/review_commands.py
  • codeframe/cli/agents_commands.py
  • codeframe/cli/checkpoint_commands.py
  • codeframe/cli/auth_commands.py
  • codeframe/cli/helpers.py
  • codeframe/cli/discovery_commands.py
  • codeframe/cli/project_commands.py
  • codeframe/cli/quality_gates_commands.py
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-11-25T19:08:37.203Z
Learning: Use feature branches from main with Conventional Commits format (feat/fix/docs scope): description
📚 Learning: 2026-01-04T06:26:12.870Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T06:26:12.870Z
Learning: Applies to codeframe/auth/**/*.py : Organize Python backend files with Auth module at codeframe/auth/ containing dependencies.py (get_current_user), manager.py (UserManager), models.py, router.py, and schemas.py

Applied to files:

  • codeframe/cli/auth_commands.py
📚 Learning: 2026-01-04T06:26:12.870Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T06:26:12.870Z
Learning: Applies to codeframe/auth/**/*.py : For authentication, use FastAPI Users with JWT tokens and mandatory authentication (no bypass mode)

Applied to files:

  • codeframe/cli/auth_commands.py
📚 Learning: 2026-01-04T06:26:12.870Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T06:26:12.870Z
Learning: Applies to web-ui/src/app/page.tsx : Implement automatic project discovery start after project creation with loading state transitions and 'Start Discovery' button for idle projects

Applied to files:

  • codeframe/cli/project_commands.py
📚 Learning: 2026-01-04T06:26:12.870Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T06:26:12.870Z
Learning: Applies to codeframe/**/*.py : Implement quality gates with multi-stage pre-completion checks (tests → type → coverage → review) and Git + SQLite + context snapshots for project state rollback

Applied to files:

  • codeframe/cli/quality_gates_commands.py
🧬 Code graph analysis (4)
codeframe/cli/agents_commands.py (2)
codeframe/cli/api_client.py (7)
  • APIClient (54-275)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • get (218-228)
  • post (230-240)
  • delete (266-275)
  • put (242-252)
codeframe/cli/helpers.py (2)
  • require_auth (21-33)
  • format_date (36-56)
codeframe/cli/checkpoint_commands.py (2)
codeframe/cli/api_client.py (6)
  • APIClient (54-275)
  • APIError (29-35)
  • AuthenticationError (38-41)
  • get (218-228)
  • post (230-240)
  • delete (266-275)
codeframe/cli/helpers.py (1)
  • require_auth (21-33)
codeframe/cli/auth_commands.py (2)
codeframe/cli/auth.py (3)
  • store_token (32-56)
  • clear_token (102-113)
  • is_authenticated (116-122)
codeframe/cli/api_client.py (5)
  • APIClient (54-275)
  • AuthenticationError (38-41)
  • get_api_base_url (44-51)
  • post (230-240)
  • get (218-228)
codeframe/cli/helpers.py (2)
tests/api/conftest.py (1)
  • api_client (67-177)
codeframe/cli/api_client.py (1)
  • APIClient (54-275)
⏰ 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: Frontend Unit Tests
  • GitHub Check: Backend Unit Tests
  • GitHub Check: claude-review
  • GitHub Check: E2E Smoke Tests (Chromium)
🔇 Additional comments (27)
codeframe/cli/auth_commands.py (2)

35-110: LGTM! Robust authentication flow.

The login command correctly uses form-encoded data with the "username" field (FastAPI Users convention) and provides comprehensive error handling for all expected scenarios.


223-256: LGTM! Proper authentication check and error handling.

The whoami command correctly pre-checks authentication status and uses the APIClient for the authenticated endpoint with appropriate error handling.

codeframe/cli/helpers.py (1)

1-56: Excellent refactoring! Successfully eliminates code duplication.

This new module effectively consolidates:

  • The require_auth helper that was previously duplicated across 12 command modules
  • The format_date helper that replaces unsafe date string slicing
  • A shared console instance for consistent output

The implementations are clean, well-documented, and defensive (handling None and short strings gracefully).

Based on learnings, this addresses the specific duplication concerns raised in past review comments for review_commands.py and agents_commands.py.

codeframe/cli/quality_gates_commands.py (1)

1-145: LGTM! Consistent use of shared helpers and clean implementation.

The module correctly leverages the shared require_auth and console from helpers, maintains consistent error handling patterns, and provides clear user guidance (e.g., suggesting the status check command after triggering a run).

codeframe/cli/discovery_commands.py (6)

1-34: LGTM! Good structure and imports.

The module is well-organized with clear docstrings and proper imports. The refactoring to use centralized require_auth and console from helpers.py addresses the previous review comment about code duplication.


36-71: LGTM!

The start command correctly handles the 409 conflict case with helpful guidance and follows consistent error handling patterns.


73-156: LGTM!

The progress command has comprehensive state handling with appropriate visual feedback. The progress bar calculation and state color mapping are correct.


158-217: LGTM!

The answer command correctly handles the workflow transition, showing either the next question or completion status with appropriate guidance.


219-272: LGTM!

The restart command properly implements the confirmation flow and provides clear error messages with guidance.


274-314: LGTM!

The generate_prd command correctly handles prerequisites and provides clear guidance when discovery isn't complete.

codeframe/cli/project_commands.py (6)

1-38: LGTM! Good module structure.

The module is well-organized with proper imports from the centralized helpers module.


40-98: LGTM!

The list_projects command handles empty projects gracefully and the date slicing pattern is safe with the conditional check.


161-204: LGTM!

The get command correctly handles the 404 case with a clear error message.


206-252: LGTM!

The status command correctly uses result.get('name') for the project name and implements a clear progress bar visualization.


254-318: LGTM!

The tasks command provides useful filtering and pagination options with clean table output.


364-454: LGTM!

The lifecycle commands (start, pause, resume) follow consistent patterns with proper error handling.

codeframe/cli/__init__.py (5)

1-31: LGTM! Good module organization.

The docstring clearly explains the CLI structure and the main app is properly configured.


98-116: LGTM!

The status command now correctly uses status['name'] and status['progress_pct'], addressing the previous review comment about incorrect dictionary keys.


168-180: LGTM!

The deprecated checkpoint command now provides clear migration guidance to the checkpoints sub-app, addressing the previous review concern.


185-265: LGTM!

The serve command has comprehensive validation and error handling. The daemon thread for browser opening is appropriate, and the error messages provide actionable guidance.


297-335: LGTM!

All 12 command groups are properly imported and registered with clear help text. The late imports are correctly annotated with noqa: E402.

codeframe/cli/checkpoint_commands.py (6)

1-35: LGTM! Good module structure.

The module is well-organized with clear docstrings, proper imports, and follows the established patterns from other CLI modules.


37-94: LGTM!

The list_checkpoints command has proper null handling for optional fields and provides helpful guidance when no checkpoints exist.


143-194: LGTM!

The get command provides comprehensive checkpoint details with good metadata display and proper 404 handling.


196-234: LGTM!

The delete command follows the established confirmation pattern with a clear warning about irreversibility.


236-288: LGTM!

The restore command has excellent UX with preview mode by default and clear diff visualization using Rich Syntax.


290-336: LGTM!

The diff command provides a clear summary of changes with file counts and colored insertions/deletions before showing the full diff.

console.print("[green]✓ Checkpoint created successfully[/green]")
console.print(f"\n[bold]ID:[/bold] {result.get('id')}")
console.print(f"[bold]Name:[/bold] {result.get('name')}")
console.print(f"[bold]Commit:[/bold] {result.get('git_commit', '')[:7]}")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential TypeError if git_commit is None.

If the API returns git_commit: null, result.get('git_commit', '') returns None (not the default ''), and None[:7] raises TypeError. Use the safe pattern from other commands.

Proposed fix
-        console.print(f"[bold]Commit:[/bold] {result.get('git_commit', '')[:7]}")
+        console.print(f"[bold]Commit:[/bold] {result.get('git_commit', '')[:7] if result.get('git_commit') else 'N/A'}")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.print(f"[bold]Commit:[/bold] {result.get('git_commit', '')[:7]}")
console.print(f"[bold]Commit:[/bold] {result.get('git_commit', '')[:7] if result.get('git_commit') else 'N/A'}")
🤖 Prompt for AI Agents
In @codeframe/cli/checkpoint_commands.py around line 129, The console.print call
uses result.get('git_commit', '')[:7] which can raise TypeError when git_commit
is None; change to use the safe pattern (e.g., (result.get('git_commit') or
'')[:7]) where this print occurs so None falls back to empty string—update the
expression in the checkpoint display code that constructs the Commit string (the
console.print line referencing result and 'git_commit').

@frankbria
frankbria merged commit 84572b0 into main Jan 5, 2026
13 checks passed
@frankbria
frankbria deleted the feature/cli-comprehensive-api-coverage branch January 5, 2026 20:23
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.

[P1] Build a CLI to match the API endpoints and typical use cases

1 participant