Version: 2.7.0 Last Updated: 2026-01-18 Status: ✅ Production Ready
Skill Seekers maintains high code quality through automated linting, comprehensive testing, and continuous integration. This document outlines the quality standards, tools, and processes used to ensure reliability and maintainability.
Quality Pillars:
- Linting - Automated code style and error detection with Ruff
- Testing - Comprehensive test coverage (1200+ tests)
- Type Safety - Type hints and validation
- Security - Security scanning with Bandit
- CI/CD - Automated validation on every commit
Ruff is an extremely fast Python linter written in Rust that combines the functionality of multiple tools:
- Flake8 (style checking)
- isort (import sorting)
- Black (code formatting)
- pyupgrade (Python version upgrades)
- And 100+ other linting rules
Why Ruff:
- ⚡ 10-100x faster than traditional linters
- 🔧 Auto-fixes for most issues
- 📦 Single tool replaces 10+ legacy tools
- 🎯 Comprehensive rule coverage
# Using uv (recommended)
uv pip install ruff
# Using pip
pip install ruff
# Development installation
pip install -e ".[dev]" # Includes ruff# Check all Python files
ruff check .
# Check specific directory
ruff check src/
# Check specific file
ruff check src/skill_seekers/cli/doc_scraper.py
# Check with auto-fix
ruff check --fix .# Check formatting (dry run)
ruff format --check .
# Apply formatting
ruff format .
# Format specific file
ruff format src/skill_seekers/cli/doc_scraper.pyRuff configuration is in pyproject.toml:
[tool.ruff]
line-length = 100
target-version = "py310"
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"SIM", # flake8-simplify
"UP", # pyupgrade
]
ignore = [
"E501", # Line too long (handled by formatter)
]
[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = [
"S101", # Allow assert in tests
]Before:
if condition1:
if condition2:
do_something()After:
if condition1 and condition2:
do_something()Why: Improves readability, reduces nesting levels.
Before:
with open('file1.txt') as f1:
with open('file2.txt') as f2:
process(f1, f2)After:
with open('file1.txt') as f1, open('file2.txt') as f2:
process(f1, f2)Why: Cleaner syntax, better resource management.
Before:
try:
risky_operation()
except Exception:
raise CustomError("Failed")After:
try:
risky_operation()
except Exception as e:
raise CustomError("Failed") from eWhy: Preserves error context, aids debugging.
Before:
for i, item in enumerate(items):
process(item) # i is never usedAfter:
for item in items:
process(item)Why: Clearer intent, removes unused variables.
Before:
for item in items:
total += 1 # item is never usedAfter:
for _ in items:
total += 1Why: Explicit that loop variable is intentionally unused.
Before:
def process(self, data, unused_arg):
return data.transform() # unused_arg never usedAfter:
def process(self, data):
return data.transform()Why: Removes dead code, clarifies function signature.
Fixed all 21 ruff linting errors across the codebase:
| Rule | Count | Files Affected | Impact |
|---|---|---|---|
| SIM102 | 7 | config_extractor.py, pattern_recognizer.py (3) | Combined nested if statements |
| SIM117 | 9 | test_example_extractor.py (3), unified_skill_builder.py | Combined with statements |
| B904 | 1 | pdf_scraper.py | Added exception chaining |
| SIM113 | 1 | config_validator.py | Removed unused enumerate counter |
| B007 | 1 | doc_scraper.py | Changed unused loop variable to _ |
| ARG002 | 1 | test fixture | Removed unused test argument |
| Total | 21 | 12 files | Zero linting errors |
Result: Clean codebase with zero linting errors, improved maintainability.
- src/skill_seekers/cli/config_extractor.py (SIM102 fixes)
- src/skill_seekers/cli/config_validator.py (SIM113 fix)
- src/skill_seekers/cli/doc_scraper.py (B007 fix)
- src/skill_seekers/cli/pattern_recognizer.py (3 × SIM102 fixes)
- src/skill_seekers/cli/test_example_extractor.py (3 × SIM117 fixes)
- src/skill_seekers/cli/unified_skill_builder.py (SIM117 fix)
- src/skill_seekers/cli/pdf_scraper.py (B904 fix)
- 6 test files (various fixes)
Critical Paths: 100% coverage required
- Core scraping logic
- Platform adaptors
- MCP tool implementations
- Configuration validation
Overall Project: >80% coverage target
Current Status:
- ✅ 1200+ tests passing
- ✅ >85% code coverage
- ✅ All critical paths covered
- ✅ CI/CD integrated
# Run all tests
pytest tests/ -v
# Run with coverage
pytest tests/ --cov=src/skill_seekers --cov-report=term --cov-report=html
# View HTML coverage report
open htmlcov/index.html# Unit tests only
pytest tests/test_*.py -v
# Integration tests
pytest tests/test_*_integration.py -v
# E2E tests
pytest tests/test_*_e2e.py -v
# MCP tests
pytest tests/test_mcp*.py -v# Slow tests (skip by default)
pytest tests/ -m "not slow"
# Run slow tests
pytest tests/ -m slow
# Async tests
pytest tests/ -m asyncio-
Unit Tests (800+ tests)
- Individual function testing
- Isolated component testing
- Mock external dependencies
-
Integration Tests (300+ tests)
- Multi-component workflows
- End-to-end feature testing
- Real file system operations
-
E2E Tests (100+ tests)
- Complete user workflows
- CLI command testing
- Platform integration testing
-
MCP Tests (63 tests)
- All 18 MCP tools
- Transport mode testing (stdio, HTTP)
- Error handling validation
Per user instructions in ~/.claude/CLAUDE.md:
"never skip any test. always make sure all test pass"
This means:
- ✅ ALL 1200+ tests must pass before commits
- ✅ No skipping tests, even if they're slow
- ✅ Add tests for new features
- ✅ Fix failing tests immediately
- ✅ Maintain or improve coverage
Skill Seekers uses GitHub Actions for automated quality checks on every commit and PR.
# .github/workflows/ci.yml (excerpt)
name: CI
on:
push:
branches: [main, development]
pull_request:
branches: [main, development]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: pip install ruff
- name: Run Ruff Check
run: ruff check .
- name: Run Ruff Format Check
run: ruff format --check .
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
python-version: ['3.10', '3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install package
run: pip install -e ".[all-llms,dev]"
- name: Run tests
run: pytest tests/ --cov=src/skill_seekers --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
file: ./coverage.xmlEvery commit and PR must pass:
- Ruff Linting - Zero linting errors
- Ruff Formatting - Consistent code style
- Pytest - All 1200+ tests passing
- Coverage - >80% code coverage
- Multi-platform - Ubuntu + macOS
- Multi-version - Python 3.10-3.13
Status: ✅ All checks passing
# Install pre-commit
pip install pre-commit
# Install hooks
pre-commit installCreate .pre-commit-config.yaml:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.7.0
hooks:
# Run ruff linter
- id: ruff
args: [--fix]
# Run ruff formatter
- id: ruff-format
- repo: local
hooks:
# Run tests before commit
- id: pytest
name: pytest
entry: pytest
language: system
pass_filenames: false
always_run: true
args: [tests/, -v]# Pre-commit hooks run automatically on git commit
git add .
git commit -m "Your message"
# → Runs ruff check, ruff format, pytest
# Run manually on all files
pre-commit run --all-files
# Skip hooks (emergency only!)
git commit -m "Emergency fix" --no-verify# 1. Standard library imports
import os
import sys
from pathlib import Path
# 2. Third-party imports
import anthropic
import requests
from fastapi import FastAPI
# 3. Local application imports
from skill_seekers.cli.doc_scraper import scrape_all
from skill_seekers.cli.adaptors import get_adaptorTool: Ruff automatically sorts imports with I rule.
# Constants: UPPER_SNAKE_CASE
MAX_PAGES = 500
DEFAULT_TIMEOUT = 30
# Classes: PascalCase
class DocumentationScraper:
pass
# Functions/variables: snake_case
def scrape_all(base_url, config):
pages_count = 0
return pages_count
# Private: leading underscore
def _internal_helper():
passdef scrape_all(base_url: str, config: dict) -> list[dict]:
"""Scrape documentation from a website using BFS traversal.
Args:
base_url: The root URL to start scraping from
config: Configuration dict with selectors and patterns
Returns:
List of page dictionaries containing title, content, URL
Raises:
NetworkError: If connection fails
InvalidConfigError: If config is malformed
Example:
>>> pages = scrape_all('https://docs.example.com', config)
>>> len(pages)
42
"""
passfrom typing import Optional, Union, Literal
def package_skill(
skill_dir: str | Path,
target: Literal['claude', 'gemini', 'openai', 'markdown'],
output_path: Optional[str] = None
) -> str:
"""Package skill for target platform."""
pass# Good: Specific exceptions with context
try:
result = risky_operation()
except NetworkError as e:
raise ScrapingError(f"Failed to fetch {url}") from e
# Bad: Bare except
try:
result = risky_operation()
except: # ❌ Too broad, loses error info
passimport logging
logger = logging.getLogger(__name__)
# Log at appropriate levels
logger.debug("Processing page: %s", url)
logger.info("Scraped %d pages", len(pages))
logger.warning("Rate limit approaching: %d requests", count)
logger.error("Failed to parse: %s", url, exc_info=True)Bandit scans for security vulnerabilities in Python code.
pip install bandit# Scan all Python files
bandit -r src/
# Scan with config
bandit -r src/ -c pyproject.toml
# Generate JSON report
bandit -r src/ -f json -o bandit-report.jsonB404: Import of subprocess module
# Review: Ensure safe usage of subprocess
import subprocess
# ✅ Safe: Using subprocess with shell=False and list arguments
subprocess.run(['ls', '-l'], shell=False)
# ❌ UNSAFE: Using shell=True with user input (NEVER DO THIS)
# This is an example of what NOT to do - security vulnerability!
# subprocess.run(f'ls {user_input}', shell=True)B605: Start process with a shell
# ❌ UNSAFE: Shell injection risk (NEVER DO THIS)
# Example of security anti-pattern:
# import os
# os.system(f'rm {filename}')
# ✅ Safe: Use subprocess with list arguments
import subprocess
subprocess.run(['rm', filename], shell=False)Security Best Practices:
- Never use
shell=Truewith user input - Always validate and sanitize user input
- Use subprocess with list arguments instead of shell commands
- Avoid dynamic command construction
# Pull latest changes
git checkout development
git pull origin development
# Create feature branch
git checkout -b feature/your-feature
# Install dependencies
pip install -e ".[all-llms,dev]"# Run linter frequently
ruff check src/skill_seekers/cli/your_file.py --fix
# Run relevant tests
pytest tests/test_your_feature.py -v
# Check formatting
ruff format src/skill_seekers/cli/your_file.py# Run all linting checks
ruff check .
ruff format --check .
# Run full test suite (REQUIRED)
pytest tests/ -v
# Check coverage
pytest tests/ --cov=src/skill_seekers --cov-report=term
# Verify all tests pass ✅# Stage changes
git add .
# Commit (pre-commit hooks will run)
git commit -m "feat: Add your feature
- Detailed change 1
- Detailed change 2
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
# Push to remote
git push origin feature/your-feature# Create PR via GitHub CLI
gh pr create --title "Add your feature" --body "Description..."
# CI checks will run automatically:
# ✅ Ruff linting
# ✅ Ruff formatting
# ✅ Pytest (1200+ tests)
# ✅ Coverage report
# ✅ Multi-platform (Ubuntu + macOS)
# ✅ Multi-version (Python 3.10-3.13)| Metric | Value | Target | Status |
|---|---|---|---|
| Linting Errors | 0 | 0 | ✅ |
| Test Count | 1200+ | 1000+ | ✅ |
| Test Pass Rate | 100% | 100% | ✅ |
| Code Coverage | >85% | >80% | ✅ |
| CI Pass Rate | 100% | >95% | ✅ |
| Python Versions | 3.10-3.13 | 3.10+ | ✅ |
| Platforms | Ubuntu, macOS | 2+ | ✅ |
| Version | Linting Errors | Tests | Coverage |
|---|---|---|---|
| v2.5.0 | 38 | 602 | 75% |
| v2.6.0 | 21 | 700+ | 80% |
| v2.7.0 | 0 | 1200+ | 85%+ |
Progress: Continuous improvement in all quality metrics.
# Update ruff
pip install --upgrade ruff
# Re-run checks
ruff check .# Ensure package is installed
pip install -e ".[all-llms,dev]"
# Clear pytest cache
rm -rf .pytest_cache/
rm -rf **/__pycache__/
# Re-run tests
pytest tests/ -v# Generate detailed coverage report
pytest tests/ --cov=src/skill_seekers --cov-report=html
# Open report
open htmlcov/index.html
# Identify untested code (red lines)
# Add tests for uncovered lines- Testing Guide - Comprehensive testing documentation
- Contributing Guide - Contribution guidelines
- API Reference - Programmatic usage
- CHANGELOG - Version history and changes
Version: 2.7.0 Last Updated: 2026-01-18 Status: ✅ Production Ready