Skip to content

[STORY] Advanced Operations Parity (SSH Keys and Indexing) #656

@jsbattig

Description

@jsbattig

Part of: #648

Part of: #EPIC_TBD

[Conversation Reference: "Story 8: Advanced Operations Parity - User Story: As a CIDX power user, I want to manage SSH keys and trigger advanced indexing operations from CLI remote mode, so that I have complete feature parity with REST/MCP interfaces."]

Story Overview

Objective: Enable advanced operations from CLI remote mode including SSH key management for repository access and advanced indexing control, providing complete parity with REST/MCP interfaces.

User Value: Power users can fully manage their CIDX environment from the command line, including setting up SSH keys for private repository access and controlling indexing operations at a granular level.

Acceptance Criteria Summary: SSH key management (create/list/delete/show-public/assign), Advanced indexing control (trigger/status/add-type).

Acceptance Criteria

AC1: Create SSH Key

Scenario: Generate new SSH key for repository access

Given the user is connected to a remote CIDX server
When the user runs "cidx keys create github-key --email [email protected]"
Then a new SSH key pair is generated on the server
And the CLI displays the public key for copying to GitHub/GitLab
And supports --key-type flag (ed25519 default, rsa)
And supports --description flag for key metadata

Technical Requirements:

  • Create keys command group
  • Implement create-key command
  • Support --email flag for key comment
  • Support --key-type flag (ed25519, rsa)
  • Support --description flag
  • Display public key in copyable format
  • Return key name for reference

AC2: List SSH Keys

Scenario: View all SSH keys configured on server

Given the user is connected to a remote CIDX server
When the user runs "cidx keys list"
Then all SSH keys are listed
And shows: name, type, fingerprint, created_at, assigned_hosts
And supports --json output format

Technical Requirements:

  • Implement list-keys command
  • Display Rich table by default
  • Show key fingerprints (not full keys)
  • Show assigned hosts for each key
  • Support --json output format

AC3: Delete SSH Key

Scenario: Remove an SSH key from server

Given the user has SSH keys configured
When the user runs "cidx keys delete github-key"
Then confirmation prompt is displayed
And upon confirmation, key is deleted
And removes key from SSH config for assigned hosts
And supports --yes flag to skip confirmation

Technical Requirements:

  • Implement delete-key command
  • Require confirmation (--yes to skip)
  • Remove from SSH config on deletion
  • Handle key not found gracefully
  • Warn about repositories using this key

AC4: Show Public Key

Scenario: Display public key for copying

Given the user has an SSH key configured
When the user runs "cidx keys show-public github-key"
Then the full public key is displayed
And formatted for direct copy/paste
And suitable for adding to GitHub/GitLab/etc

Technical Requirements:

  • Implement show-public command
  • Display complete public key
  • Format appropriately for copying
  • Handle key not found gracefully

AC5: Assign Key to Host

Scenario: Configure SSH key for specific host

Given the user has an SSH key
When the user runs "cidx keys assign github-key github.com"
Then the key is configured for that host in SSH config
And subsequent git operations to github.com use this key
And supports --force flag to replace existing assignment

Technical Requirements:

  • Implement assign-key command
  • Update SSH config with Host entry
  • Support --force flag for override
  • Validate hostname format
  • Show confirmation of assignment

AC6: Trigger Re-indexing

Scenario: Manually trigger indexing for repository

Given the user has an activated repository
When the user runs "cidx index trigger my-repo"
Then re-indexing is triggered for the repository
And job_id is returned for monitoring
And supports --clear flag to rebuild from scratch
And supports --types flag to specify index types

Technical Requirements:

  • Create index command group (if not exists)
  • Implement trigger command
  • Support --clear flag for full rebuild
  • Support --types flag (semantic, fts, temporal, scip)
  • Return job_id for async monitoring

AC7: Check Index Status

Scenario: View indexing status for repository

Given the user has a repository
When the user runs "cidx index status my-repo"
Then index status is displayed for all types:
  - semantic: indexed (12,345 files)
  - fts: indexed (12,345 files)
  - temporal: not indexed
  - scip: indexed (5 projects)
And shows last indexed timestamp
And shows health indicators

Technical Requirements:

  • Implement index status command
  • Show status for all index types
  • Show file counts per type
  • Show last indexed timestamps
  • Support --json output format

AC8: Add Index Type

Scenario: Add new index type to existing repository

Given the user has a repository with basic indexing
When the user runs "cidx index add-type my-repo scip"
Then SCIP indexing is triggered for the repository
And job_id is returned for monitoring
And validates index type is valid

Technical Requirements:

  • Implement add-type command
  • Validate index type parameter
  • Return job_id for async monitoring
  • Handle already-exists case gracefully
  • Show estimated time if available

Implementation Status

Progress Tracking:

  • Core implementation complete
  • Unit tests passing (X/Y tests)
  • Integration tests passing (X/Y tests)
  • E2E tests passing (X/Y tests)
  • Code review approved
  • Manual E2E testing completed by Claude Code
  • Documentation updated

Completion: 0/7 tasks complete (0%)

Technical Implementation Details

Component Structure

src/code_indexer/client/
  ssh_api_client.py         # SSHAPIClient class
    - create_key()
    - list_keys()
    - delete_key()
    - show_public()
    - assign_host()

  index_api_client.py       # IndexAPIClient class
    - trigger_reindex()
    - get_index_status()
    - add_index_type()

src/code_indexer/cli/commands/
  keys.py                   # SSH key management commands
  index.py                  # Indexing control commands (extend if exists)

Command Group Structure

@cli.group()
@requires_mode(remote=True)
def keys():
    """SSH key management for repository access"""
    pass

@keys.command('create')
@click.argument('name')
@click.option('--email', help='Email for key comment')
@click.option('--key-type', type=click.Choice(['ed25519', 'rsa']), default='ed25519')
@click.option('--description', help='Key description/purpose')
@click.option('--json', 'output_json', is_flag=True)
def create_key(name, email, key_type, description, output_json):
    """Create a new SSH key pair"""
    client = get_ssh_api_client()
    result = client.create_key(name, email, key_type, description)
    # Display public key for copying

@keys.command('list')
@click.option('--json', 'output_json', is_flag=True)
def list_keys(output_json):
    """List all SSH keys"""
    pass

@cli.group()
@requires_mode(remote=True)
def index():
    """Index management commands"""
    pass

@index.command('trigger')
@click.argument('repository')
@click.option('--clear', is_flag=True, help='Rebuild from scratch')
@click.option('--types', multiple=True, type=click.Choice(['semantic', 'fts', 'temporal', 'scip']))
@click.option('--json', 'output_json', is_flag=True)
def trigger_index(repository, clear, types, output_json):
    """Trigger re-indexing for repository"""
    pass

API Client Pattern

class SSHAPIClient:
    def __init__(self, remote_client: CIDXRemoteAPIClient):
        self.client = remote_client

    async def create_key(
        self,
        name: str,
        email: Optional[str] = None,
        key_type: str = 'ed25519',
        description: Optional[str] = None
    ) -> SSHKeyResult:
        response = await self.client.post(
            "/api/v1/ssh/keys",
            json={
                "name": name,
                "email": email,
                "key_type": key_type,
                "description": description
            }
        )
        return SSHKeyResult(**response)

class IndexAPIClient:
    async def trigger_reindex(
        self,
        repository: str,
        clear: bool = False,
        index_types: Optional[List[str]] = None
    ) -> TriggerResult:
        response = await self.client.post(
            f"/api/v1/index/{repository}/trigger",
            json={
                "clear": clear,
                "index_types": index_types or []
            }
        )
        return TriggerResult(**response)

Testing Requirements

Unit Test Coverage

  • SSH key creation sends correct payload
  • Key listing parses response correctly
  • Key deletion handles confirmation
  • Index trigger sends correct parameters
  • Index status parsing works correctly

Integration Test Coverage

  • Create key generates valid key pair
  • List keys shows all keys
  • Assign key updates SSH config
  • Trigger index creates background job
  • Index status reflects actual state

E2E Test Coverage

  • Full SSH workflow: create -> assign -> use
  • Full index workflow: trigger -> monitor -> verify
  • Add index type triggers correct indexer
  • Key deletion removes from config

Performance Requirements

Response Time Targets

  • Key operations: <2 seconds
  • Index trigger (response): <2 seconds (job is async)
  • Index status: <2 seconds

Resource Requirements

  • Memory: Minimal
  • Network: Standard REST calls
  • CPU: Key generation on server

Error Handling Specifications

User-Friendly Error Messages

Error: SSH key 'github-key' already exists
Suggestion: Use different name or delete existing key first

Error: Host 'github.com' already has assigned key: other-key
Suggestion: Use --force to replace existing assignment

Error: Invalid index type: 'invalid'
Valid types: semantic, fts, temporal, scip

Error: SCIP indexing not supported for this repository
Details: No supported languages detected
Supported: Python, TypeScript, Java, C#, Go, Kotlin

Recovery Guidance

  • Key exists: Suggest different name or delete
  • Host assigned: Suggest --force flag
  • Invalid index type: Show valid options
  • Indexing not supported: Explain requirements

Definition of Done

Functional Completion

  • SSH key create/list/delete/show works
  • Key assignment to hosts works
  • Index trigger with options works
  • Index status shows all types
  • Add index type works

Quality Validation

  • >90% test coverage achieved
  • All tests passing (unit, integration, E2E)
  • Code review approved
  • Manual testing validated with evidence
  • Performance benchmarks met

Integration Readiness

  • Story delivers working, deployable software
  • Full vertical slice implemented
  • No broken functionality
  • Documentation complete

Story Points: Medium (8 operations)
Priority: Low (power user features)
Dependencies: Story 1 (Mode Detection)
Success Metric: Complete feature parity with REST/MCP

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions