Skip to content

Implementation Simplification Refactor: Keep All Features, Reduce Complexity 30% #122

@jeremyeder

Description

@jeremyeder

AgentReady Implementation Simplification Plan

Date: 2025-11-23
Goal: Keep all features, reduce implementation complexity through refactoring
Target: -30% LOC reduction (~1,880 lines) without removing features

Executive Summary

AgentReady has grown to 64 modules and ~6,300 LOC across 8 commands. While well-architected, it carries complexity debt from:

  • Duplicated validation/security patterns across modules
  • Over-engineered abstractions in some areas
  • Scattered service initialization logic
  • Template duplication across languages
  • Test setup duplication

This plan reduces complexity through refactoring, not feature removal.


Current State Assessment

Codebase Metrics

  • 64 Python modules across 7 packages
  • 15 Jinja2 templates for bootstrap
  • 169 test cases across 39 test files
  • 8 CLI commands: assess, bootstrap, learn, align, assess-batch, demo, research, repomix
  • 5 output formats: HTML, Markdown, JSON, CSV, Multi-HTML

Complexity Hotspots

  1. Scattered security validation - path validation duplicated across 5+ modules (~125 lines each)
  2. Reporter duplication - 5 reporters share 40% common code
  3. Service initialization - duplicated dependency injection patterns
  4. Config validation - 125 lines of manual validation in CLI
  5. Bootstrap template duplication - similar patterns across language templates
  6. Test fixture duplication - 169 tests with significant setup overlap

Phase 1: Consolidate Duplicated Patterns (Week 1-2)

1. Centralize Security Validation

Problem:

# cli/main.py (125 lines of validation)
# reporters/html.py (path sanitization)
# services/bootstrap.py (path validation)
# utils/privacy.py (path sanitization)
# models/repository.py (path validation)

All modules duplicate path traversal checks, XSS prevention, and input validation.

Solution:
Create src/agentready/utils/security.py:

"""Centralized security validation."""
from pathlib import Path
from typing import Any


def validate_path(
    path: str | Path,
    allow_system_dirs: bool = False,
    must_exist: bool = False
) -> Path:
    """Validate and sanitize file paths.

    Args:
        path: Path to validate
        allow_system_dirs: Allow /etc, /usr, /bin, etc.
        must_exist: Raise if path doesn't exist

    Returns:
        Resolved, validated Path

    Raises:
        ValueError: If path is invalid or unsafe
    """
    # Path traversal prevention
    # System directory checks
    # Existence validation
    # Return sanitized Path


def validate_config_dict(data: dict, schema: dict) -> dict:
    """Validate configuration dictionary against schema.

    Args:
        data: Config data to validate
        schema: JSON schema or type specification

    Returns:
        Validated config dict

    Raises:
        ValueError: If validation fails
    """
    # Type checking
    # Unknown key rejection
    # Required field validation
    # Return validated dict


def sanitize_for_html(text: str) -> str:
    """Sanitize text for HTML output (XSS prevention).

    Args:
        text: Unsafe text

    Returns:
        HTML-safe text
    """
    # XSS prevention
    # Entity escaping
    # Return safe text


def sanitize_for_json(text: str) -> str:
    """Sanitize text for JSON output.

    Args:
        text: Unsafe text

    Returns:
        JSON-safe text
    """
    # JSON injection prevention
    # Return safe text

Refactor locations:

  • cli/main.py - replace 125-line validation with validate_config_dict() call
  • reporters/html.py - replace XSS code with sanitize_for_html()
  • services/bootstrap.py - replace path checks with validate_path()
  • All modules doing path validation

Impact:

  • -200 LOC (net: +100 in utils, -300 in duplicated code)
  • Improved consistency (single source of truth for security)
  • Easier to audit (one module vs scattered code)

2. Create Shared Reporter Base Class

Problem:
All 5 reporters duplicate:

  • Path handling (output directory, file naming)
  • Metadata formatting (timestamp, repository name)
  • File writing boilerplate
  • Error handling
# Each reporter has ~40% duplicated code:
# - _ensure_output_dir()
# - _generate_filename()
# - _format_metadata()
# - _write_file()

Solution:
Create src/agentready/reporters/base.py:

"""Base class for all reporters."""
from abc import ABC, abstractmethod
from pathlib import Path
from agentready.models import Assessment


class BaseReporter(ABC):
    """Base reporter with common functionality."""

    def __init__(self, output_dir: Path):
        self.output_dir = output_dir

    def generate_report(self, assessment: Assessment) -> Path:
        """Template method for report generation."""
        self._ensure_output_dir()
        content = self._generate_content(assessment)
        filepath = self._write_file(content, assessment)
        return filepath

    @abstractmethod
    def _generate_content(self, assessment: Assessment) -> str | bytes:
        """Subclass implements format-specific generation."""
        pass

    @abstractmethod
    def _get_file_extension(self) -> str:
        """Return file extension (.html, .md, .json, .csv)."""
        pass

    def _ensure_output_dir(self) -> None:
        """Create output directory if needed."""
        # Common implementation

    def _generate_filename(self, assessment: Assessment) -> str:
        """Generate filename with timestamp."""
        # Common implementation

    def _write_file(self, content: str | bytes, assessment: Assessment) -> Path:
        """Write content to file."""
        # Common implementation

Refactor reporters:

# html.py
class HTMLReporter(BaseReporter):
    def _generate_content(self, assessment: Assessment) -> str:
        # HTML-specific logic only

    def _get_file_extension(self) -> str:
        return ".html"


# markdown.py
class MarkdownReporter(BaseReporter):
    def _generate_content(self, assessment: Assessment) -> str:
        # Markdown-specific logic only

    def _get_file_extension(self) -> str:
        return ".md"

Impact:

  • -300 LOC (remove duplicated code from 5 reporters)
  • DRY principle applied
  • Easier to add new reporters (just implement _generate_content())

3. Consolidate Service Initialization

Problem:
Services duplicate dependency injection patterns:

# scanner.py
class Scanner:
    def __init__(self, config):
        self.assessors = self._init_assessors()
        self.language_detector = LanguageDetector()
        self.repository_manager = RepositoryManager()


# learning_service.py
class LearningService:
    def __init__(self, config):
        self.pattern_extractor = PatternExtractor()
        self.llm_enricher = self._init_llm() if api_key else None

Every service initializes dependencies in __init__ with duplicated logic.

Solution:
Create src/agentready/services/registry.py:

"""Service registry and dependency injection."""
from typing import Type, TypeVar, Callable


T = TypeVar('T')


class ServiceRegistry:
    """Simple DI container for services."""

    def __init__(self):
        self._services = {}
        self._factories = {}

    def register(self, interface: Type[T], factory: Callable[[], T]):
        """Register a service factory."""
        self._factories[interface] = factory

    def get(self, interface: Type[T]) -> T:
        """Get or create service instance (singleton)."""
        if interface not in self._services:
            factory = self._factories[interface]
            self._services[interface] = factory()
        return self._services[interface]

    def clear(self):
        """Clear all services (for testing)."""
        self._services.clear()


# Global registry
_registry = ServiceRegistry()


def get_service(interface: Type[T]) -> T:
    """Get service from global registry."""
    return _registry.get(interface)

Usage in services:

# scanner.py
from .registry import get_service

class Scanner:
    def __init__(self):
        self.language_detector = get_service(LanguageDetector)
        self.repository_manager = get_service(RepositoryManager)
        # No manual initialization needed

Impact:

  • -150 LOC (remove duplicated initialization across 13 services)
  • Clearer service lifecycle
  • Easier testing (can inject mocks via registry)

Phase 2: Simplify Over-Engineered Areas (Week 3-4)

4. Use Pydantic for Config Validation

Problem:
cli/main.py has 125 lines of manual config validation:

# Manually check every field type
if not isinstance(config.get("weights"), dict):
    raise ValueError(...)

# Manually reject unknown keys
allowed_keys = {"weights", "theme", "excluded_attributes"}
for key in config:
    if key not in allowed_keys:
        raise ValueError(...)

# Manually validate nested structures
for attr_id, weight in config["weights"].items():
    if not isinstance(weight, (int, float)):
        raise ValueError(...)

Solution:
Replace with Pydantic models in src/agentready/models/config.py:

"""Configuration models with validation."""
from pydantic import BaseModel, Field, field_validator


class ThemeConfig(BaseModel):
    """Theme configuration."""
    name: str = "default"
    primary_color: str = "#1a56db"
    secondary_color: str = "#7c3aed"
    # Auto-validates types, provides JSON schema


class AgentReadyConfig(BaseModel):
    """Main configuration model."""
    weights: dict[str, float] = Field(default_factory=dict)
    theme: ThemeConfig = Field(default_factory=ThemeConfig)
    excluded_attributes: list[str] = Field(default_factory=list)
    output_dir: str = ".agentready"

    @field_validator("weights")
    def validate_weights(cls, v):
        """Ensure weights are 0-100."""
        for attr_id, weight in v.items():
            if not 0 <= weight <= 100:
                raise ValueError(f"Weight for {attr_id} must be 0-100")
        return v

    class Config:
        extra = "forbid"  # Reject unknown keys


# Usage
config = AgentReadyConfig.model_validate(yaml_data)

Impact:

  • -100 LOC (125 lines manual validation → 25 lines Pydantic models)
  • Get JSON schema generation for free
  • Better error messages
  • Type hints for IDE autocomplete

5. Reduce Template Complexity via Inheritance

Problem:
Bootstrap has 15 Jinja2 templates with significant duplication:

templates/bootstrap/
├── python/
│   ├── github-actions-tests.yml       # 80% similar to js/github-actions-tests.yml
│   ├── github-actions-security.yml    # 80% similar to js/github-actions-security.yml
│   ├── pre-commit-config.yaml         # Language-specific hooks
├── javascript/
│   ├── github-actions-tests.yml
│   ├── github-actions-security.yml
│   ├── pre-commit-config.yaml
├── go/
│   └── ...

Solution:
Use Jinja2 template inheritance:

templates/bootstrap/
├── _base/
│   ├── github-actions-tests.yml.j2    # Base template with blocks
│   ├── github-actions-security.yml.j2
│   └── pre-commit-config.yaml.j2
├── python/
│   ├── github-actions-tests.yml.j2    # {% extends "_base/..." %} + Python-specific blocks
│   └── pre-commit-config.yaml.j2
├── javascript/
│   ├── github-actions-tests.yml.j2    # {% extends "_base/..." %} + JS-specific blocks
│   └── pre-commit-config.yaml.j2

Base template example:

{# _base/github-actions-tests.yml.j2 #}
name: Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      {% block setup_environment %}
      {# Language-specific setup #}
      {% endblock %}

      {% block install_dependencies %}
      {# Language-specific install #}
      {% endblock %}

      {% block run_tests %}
      {# Language-specific test command #}
      {% endblock %}

Python template:

{# python/github-actions-tests.yml.j2 #}
{% extends "_base/github-actions-tests.yml.j2" %}

{% block setup_environment %}
      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'
{% endblock %}

{% block install_dependencies %}
      - run: pip install -e ".[dev]"
{% endblock %}

{% block run_tests %}
      - run: pytest --cov
{% endblock %}

Impact:

  • 15 templates → 8 templates (1 base set + 7 language-specific overrides)
  • Easier to update common patterns (edit base template once)
  • Less duplication

6. Simplify Theme System

Problem:
Current theme system has 84 config values (14 RGB colors × 6 presets):

# .agentready-config.yaml
theme:
  name: custom
  primary_color: "#1a56db"
  secondary_color: "#7c3aed"
  background_color: "#ffffff"
  text_color: "#1f2937"
  border_color: "#e5e7eb"
  success_color: "#10b981"
  warning_color: "#f59e0b"
  error_color: "#ef4444"
  info_color: "#3b82f6"
  # ... 5 more colors

Users rarely customize themes beyond dark/light mode.

Solution:
Use CSS variables + algorithmic color generation:

# reporters/themes.py
from dataclasses import dataclass


@dataclass
class Theme:
    """Theme defined by 2-3 base colors."""
    name: str
    primary: str      # Main brand color
    background: str   # Light or dark background

    def to_css_vars(self) -> dict[str, str]:
        """Generate full color palette from base colors."""
        # Use color theory to derive:
        # - secondary (complementary to primary)
        # - success/warning/error (semantic colors)
        # - text (contrast-safe against background)
        # - borders (background + 10% brightness)

        return {
            "--primary": self.primary,
            "--secondary": self._derive_secondary(self.primary),
            "--background": self.background,
            "--text": self._derive_text(self.background),
            "--success": "#10b981",  # Universal semantic colors
            "--warning": "#f59e0b",
            "--error": "#ef4444",
            # ...
        }


# Presets
THEMES = {
    "default": Theme("default", "#1a56db", "#ffffff"),
    "dark": Theme("dark", "#3b82f6", "#1f2937"),
}

Impact:

  • -150 LOC in theme system
  • Config: 14 colors → 2-3 colors
  • Easier theme creation (just pick primary + background)
  • Still generates full palette

Phase 3: Better Abstractions (Week 5-6)

7. Create Assessor Registry Pattern

Problem:
cli/main.py manually imports and instantiates all assessors:

from agentready.assessors.documentation import (
    ClaudeMdAssessor,
    ReadmeAssessor,
    ApiDocsAssessor,
    # ... 10 more
)
from agentready.assessors.code_quality import (
    TypeAnnotationsAssessor,
    LinterConfigAssessor,
    # ... 8 more
)

# Then manually create instances
assessors = [
    ClaudeMdAssessor(),
    ReadmeAssessor(),
    ApiDocsAssessor(),
    # ... 20+ more
]

Solution:
Auto-discovery with decorator:

# assessors/base.py
_assessor_registry = {}

def register_assessor(attribute_id: str):
    """Decorator to auto-register assessors."""
    def decorator(cls):
        _assessor_registry[attribute_id] = cls
        return cls
    return decorator


def get_all_assessors() -> list[BaseAssessor]:
    """Get instances of all registered assessors."""
    return [cls() for cls in _assessor_registry.values()]


# Usage in assessor files
@register_assessor("claude_md_file")
class ClaudeMdAssessor(BaseAssessor):
    # Implementation
    pass


@register_assessor("readme_present")
class ReadmeAssessor(BaseAssessor):
    # Implementation
    pass


# In cli/main.py - just import assessor modules, registry auto-populates
from agentready.assessors import documentation, code_quality, testing, structure

assessors = get_all_assessors()  # Auto-discovered!

Impact:

  • -80 LOC in main.py (remove manual imports/instantiation)
  • Easier to add assessors (just define class with decorator)
  • No manual registry maintenance

8. Unify Batch and Single Assessment Paths

Problem:
batch_scanner.py is a thin wrapper:

# services/batch_scanner.py (200 lines)
class BatchScanner:
    def scan_repositories(self, repo_paths: list[Path]):
        results = []
        for repo_path in repo_paths:
            scanner = Scanner()  # Create single scanner
            result = scanner.scan(repo_path)
            results.append(result)
        return results

This is just a for-loop over single scanner.

Solution:
Make Scanner handle both:

# services/scanner.py
class Scanner:
    def scan(self, repo_paths: Path | list[Path]) -> Assessment | list[Assessment]:
        """Scan single repo or batch."""
        if isinstance(repo_paths, Path):
            return self._scan_single(repo_paths)
        else:
            return [self._scan_single(p) for p in repo_paths]

    def _scan_single(self, repo_path: Path) -> Assessment:
        # Existing single-repo logic
        pass

Impact:

  • -200 LOC (delete batch_scanner.py entirely)
  • Single code path = easier maintenance
  • Same API for CLI (scanner handles single vs batch internally)

9. Consolidate Research Service Operations

Problem:
Research operations split across 2 files:

# services/research_loader.py (150 lines)
class ResearchLoader:
    def load_report(self) -> dict: ...
    def validate_schema(self) -> bool: ...


# services/research_formatter.py (100 lines)
class ResearchFormatter:
    def format_for_display(self, data: dict) -> str: ...
    def format_citations(self, citations: list) -> str: ...

These are tightly coupled (formatter needs loader data).

Solution:
Merge into single service:

# services/research_service.py (200 lines)
class ResearchService:
    """Unified research report operations."""

    def load_report(self) -> dict:
        # Loading logic
        pass

    def validate_schema(self) -> bool:
        # Validation logic
        pass

    def format_for_display(self, data: dict) -> str:
        # Formatting logic
        pass

    def format_citations(self, citations: list) -> str:
        # Citation formatting
        pass

Impact:

  • -100 LOC (remove overhead of 2 separate classes)
  • Clearer module boundaries (all research ops in one place)
  • 13 services → 12 services

Phase 4: Improve Test Architecture (Week 7)

10. Create Shared Test Fixtures

Problem:
169 tests duplicate fixture setup:

# tests/test_scanner.py
def test_scan():
    # Create temp repo
    repo_path = tmp_path / "test-repo"
    repo_path.mkdir()
    (repo_path / "README.md").write_text("# Test")
    (repo_path / "CLAUDE.md").write_text("# Context")
    # ... 20 lines of setup

    scanner = Scanner()
    result = scanner.scan(repo_path)
    assert result.score > 0


# tests/test_learning.py
def test_learn():
    # Create temp repo (same setup!)
    repo_path = tmp_path / "test-repo"
    repo_path.mkdir()
    (repo_path / "README.md").write_text("# Test")
    (repo_path / "CLAUDE.md").write_text("# Context")
    # ... 20 lines of setup

    learning_service = LearningService()
    # ...

Solution:
Shared fixtures in tests/conftest.py:

# tests/conftest.py
import pytest
from pathlib import Path


@pytest.fixture
def sample_repo(tmp_path):
    """Create a sample repository with common files."""
    repo_path = tmp_path / "test-repo"
    repo_path.mkdir()

    # Standard files
    (repo_path / "README.md").write_text("# Test Project")
    (repo_path / "CLAUDE.md").write_text("# Context")
    (repo_path / ".gitignore").write_text("*.pyc\n__pycache__/")

    # Python files
    src_dir = repo_path / "src"
    src_dir.mkdir()
    (src_dir / "__init__.py").write_text("")
    (src_dir / "main.py").write_text("def main(): pass")

    # Tests
    test_dir = repo_path / "tests"
    test_dir.mkdir()
    (test_dir / "test_main.py").write_text("def test_main(): pass")

    return repo_path


@pytest.fixture
def sample_assessment(sample_repo):
    """Create a sample assessment result."""
    from agentready.services.scanner import Scanner
    scanner = Scanner()
    return scanner.scan(sample_repo)


@pytest.fixture
def mock_anthropic_client():
    """Mock Anthropic API client."""
    from unittest.mock import Mock
    client = Mock()
    client.messages.create.return_value = Mock(
        content=[Mock(text='{"skill_description": "Test skill"}')]
    )
    return client

Usage:

# tests/test_scanner.py
def test_scan(sample_repo):
    scanner = Scanner()
    result = scanner.scan(sample_repo)
    assert result.score > 0
    # No setup needed!


# tests/test_learning.py
def test_learn(sample_assessment):
    learning_service = LearningService()
    skills = learning_service.extract_patterns(sample_assessment)
    assert len(skills) > 0
    # No setup needed!

Impact:

  • -400 LOC in tests (remove duplicated setup)
  • Faster test execution (pytest caches fixtures)
  • More maintainable tests

11. Reduce Integration Test Complexity

Problem:
Some integration tests spawn entire workflows when unit tests would suffice:

# tests/integration/test_full_workflow.py (300 lines)
def test_assess_to_report():
    """Test entire assess → report → align workflow."""
    # Creates repo
    # Runs scanner
    # Generates all 5 report formats
    # Runs all fixers
    # Validates output files
    # Takes 10+ seconds

Solution:
Convert some integration tests to unit tests:

# tests/unit/test_scanner.py
def test_scanner_calls_assessors(mocker, sample_repo):
    """Unit test: scanner calls assessors correctly."""
    mock_assessor = mocker.patch("agentready.services.scanner.get_all_assessors")
    scanner = Scanner()
    scanner.scan(sample_repo)
    mock_assessor.assert_called_once()
    # Fast unit test with mocks


# Keep only critical integration tests
# tests/integration/test_full_workflow.py
def test_assess_and_html_report_integration(sample_repo):
    """Integration test: assess + HTML report (most common path)."""
    # Test only the most common user workflow
    # Skip testing all 5 report formats (those are unit tests)

Impact:

  • -200 LOC in integration tests
  • 2x faster test suite (unit tests run in milliseconds vs seconds)
  • Still maintain coverage with focused unit tests

Summary of Expected Outcomes

Code Reduction

Phase Changes LOC Saved
1. Consolidate Patterns Security utils, reporter base, service registry -650
2. Simplify Over-Engineering Pydantic config, template inheritance, theme system -250
3. Better Abstractions Assessor registry, unify batch, merge research -380
4. Test Improvements Shared fixtures, reduce integration tests -600
Total -1,880 LOC

Percentage: ~30% reduction (6,300 → 4,420 LOC)

Module Count

  • Before: 64 modules + 15 templates = 79 files
  • After: 58 modules + 8 templates = 66 files
  • Reduction: -13 files (16%)

Maintainability Improvements

  • ✅ Single source of truth for security validation
  • ✅ DRY principle applied to reporters and services
  • ✅ Clearer service boundaries and responsibilities
  • ✅ Easier to add assessors (just use decorator)
  • ✅ Faster test suite (2x improvement)
  • ✅ Better type safety (Pydantic models)

Implementation Checklist

Week 1-2: Phase 1

  • Create utils/security.py with centralized validation
  • Refactor all modules to use security utils
  • Create reporters/base.py with shared reporter logic
  • Refactor 5 reporters to extend base class
  • Create services/registry.py for DI
  • Update services to use registry
  • Run test suite (ensure all pass)
  • Update documentation

Week 3-4: Phase 2

  • Create Pydantic config models in models/config.py
  • Replace manual validation in cli/main.py
  • Refactor bootstrap templates to use inheritance
  • Update services/bootstrap.py to use new templates
  • Simplify theme system to 2-3 base colors
  • Update HTML reporter to use new theme system
  • Run test suite
  • Update configuration docs

Week 5-6: Phase 3

  • Add @register_assessor decorator to assessors/base.py
  • Annotate all assessor classes with decorator
  • Remove manual imports from cli/main.py
  • Update Scanner to handle single/batch
  • Delete batch_scanner.py
  • Merge research_loader.py + research_formatter.pyresearch_service.py
  • Run test suite
  • Update API docs

Week 7: Phase 4

  • Create shared fixtures in tests/conftest.py
  • Refactor tests to use fixtures
  • Identify integration tests that can be unit tests
  • Convert 10-15 integration → unit tests
  • Run full test suite
  • Verify 90%+ coverage maintained
  • Update testing documentation

Risk Mitigation

Testing Strategy

  • Before each phase: Run full test suite, ensure 100% pass
  • After each refactor: Run affected tests
  • End of each week: Full regression test
  • CI/CD: All checks must pass before merging

Rollback Plan

  • Use feature branches for each phase
  • Keep original code until phase verified
  • Tag stable points: v1.0-pre-refactor, v1.1-phase1-complete, etc.

Breaking Changes

NONE - This is pure refactoring:

  • CLI commands unchanged
  • Config format unchanged (Pydantic validates same structure)
  • Report outputs unchanged
  • All features retained

Success Metrics

Quantitative

  • ✅ Reduce LOC by 30% (6,300 → 4,420)
  • ✅ Reduce file count by 16% (79 → 66)
  • ✅ Improve test speed by 2x
  • ✅ Maintain 90%+ test coverage

Qualitative

  • ✅ Easier to onboard new contributors (clearer patterns)
  • ✅ Easier to add assessors (decorator pattern)
  • ✅ Easier to add reporters (base class)
  • ✅ More consistent security (centralized validation)
  • ✅ Better type safety (Pydantic)

Post-Simplification Next Steps

After completing this refactor:

  1. Documentation Sprint - Update all docs to reflect new patterns
  2. Performance Profiling - Identify any new bottlenecks from abstractions
  3. Community Feedback - Get input from contributors on new structure
  4. Feature Development - Resume adding features with cleaner codebase

Appendix: Key Files to Refactor

High Priority (Phase 1)

  • src/agentready/cli/main.py (512 lines) - config validation
  • src/agentready/reporters/html.py (300+ lines) - security/base class
  • src/agentready/reporters/markdown.py (150+ lines) - base class
  • src/agentready/reporters/json_reporter.py (50+ lines) - base class
  • src/agentready/reporters/csv_reporter.py (100+ lines) - base class
  • src/agentready/reporters/multi_html.py (200+ lines) - base class

Medium Priority (Phase 2-3)

  • src/agentready/services/bootstrap.py (500 lines) - template inheritance
  • src/agentready/services/batch_scanner.py (200 lines) - DELETE
  • src/agentready/services/research_loader.py (150 lines) - MERGE
  • src/agentready/services/research_formatter.py (100 lines) - MERGE
  • templates/bootstrap/ (15 files) - inheritance

Low Priority (Phase 4)

  • tests/ (39 files, 169 tests) - shared fixtures

Cold Start Instructions for AI Agent

Context: You are refactoring AgentReady to reduce implementation complexity while keeping all features.

Starting Point:

  1. Read this document: .plans/implementation-simplification-refactor.md
  2. Review current architecture: src/agentready/ (64 modules)
  3. Check test coverage: pytest --cov (should be 90%+)

Execution:

  1. Start with Phase 1, Week 1-2
  2. Create feature branch: git checkout -b refactor/phase-1-consolidate-patterns
  3. Implement changes from checklist
  4. Run tests after each change: pytest
  5. Commit incrementally with clear messages
  6. When phase complete, open PR for review

Key Principles:

  • ✅ Keep all features (no deletions)
  • ✅ Maintain test coverage (90%+)
  • ✅ Preserve CLI/config compatibility
  • ✅ Focus on DRY and single responsibility
  • ❌ Don't add new features (pure refactor)
  • ❌ Don't change external APIs

Questions to Ask:

  • Does this refactor maintain the same external behavior?
  • Are tests still passing?
  • Is the code more maintainable after this change?
  • Could a new contributor understand this pattern?

End Goal: Same AgentReady functionality, 30% less code, better maintainability.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions