AI Web FeedsAI Web FeedsOpen web AI reader
  • Contributing
    Documentation

    Conventional Commits

    Guide to using Conventional Commits specification in ai-web-feeds

    Source: apps/web/content/docs/contributing/conventional-commits.mdx

    Overview

    ai-web-feeds uses the Conventional Commits specification for all commit messages. This provides a structured format that enables automated changelog generation, semantic versioning, and clear project history.

    Format

    Each commit message consists of a header, optional body, and optional footer:

    <type>(<scope>): <subject>
    
    [optional body]
    
    [optional footer]

    Header (Required)

    The header has a special format that includes a type, optional scope, and subject:

    <type>(<scope>): <subject>
    │       │            │
    │       │            └─> Summary in present tense. Not capitalized. No period at end.
    │       │
    │       └─> Scope: core|analytics|monitoring|nlp|cli|web|docs|tests|deps|ci|etc.
    
    └─> Type: feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert

    Rules:

    • Maximum 100 characters
    • Type and subject are required
    • Scope is recommended but optional
    • Subject is lowercase, imperative mood ("add" not "added" or "adds")
    • No period at the end

    Commit Types

    TypeDescriptionChangelog SectionExample
    featNew featureFeaturesfeat(core): add RSS feed parser
    fixBug fixBug Fixesfix(analytics): correct topic count calculation
    docsDocumentation onlyDocumentationdocs(api): update fetch endpoint examples
    styleCode style/formatting (no logic change)-style(core): format with ruff
    refactorCode refactoring (no feature/fix)-refactor(storage): simplify query builder
    perfPerformance improvementPerformanceperf(nlp): optimize embedding generation
    testAdd/update tests-test(validate): add edge case coverage
    buildBuild system/dependencies-build(deps): update pydantic to 2.5.0
    ciCI/CD changes-ci(workflow): add caching for npm deps
    choreOther changes (no src/test modification)-chore(release): bump version to 0.2.0
    revertRevert previous commit-revert(feat): remove experimental feature

    Scopes

    Scopes indicate which part of the codebase is affected:

    Core Package Scopes

    • core - Core functionality
    • models - Data models and schemas
    • storage - Database and persistence
    • load - Feed loading and fetching
    • validate - Validation logic
    • export - Export functionality
    • enrich - Enrichment pipeline
    • logger - Logging utilities
    • utils - Utility functions
    • config - Configuration management

    Phase-Specific Scopes

    • analytics - Phase 002: Analytics & Discovery
    • discovery - Phase 002: Feed discovery
    • monitoring - Phase 003: Real-time monitoring
    • realtime - Phase 003: Real-time features
    • nlp - Phase 005: NLP/AI features
    • ai - Phase 005: AI-powered features

    Component Scopes

    • cli - Command-line interface
    • web - Web documentation site
    • api - API endpoints

    Infrastructure Scopes

    • db - Database changes
    • schema - Schema definitions
    • migrations - Database migrations
    • data - Data files (feeds.yaml, topics.yaml)

    Meta Scopes

    • docs - Documentation
    • tests - Test infrastructure
    • deps - Dependencies
    • ci - CI/CD pipeline
    • tooling - Development tools
    • release - Release management

    Examples

    Feature Addition

    feat(analytics): add topic trending analysis
    
    Implement z-score based trending detection for topics with
    configurable thresholds and time windows.
    
    Closes #123

    Bug Fix

    fix(load): handle malformed RSS feed dates
    
    Parse dates with lenient mode and use the current timestamp
    when feed dates are invalid or missing.
    
    Fixes #456

    Documentation

    docs(cli): add examples for export command
    
    Add usage examples for JSON, OPML, and CSV export formats
    with filtering options.

    Breaking Change

    feat(api)!: redesign feed validation endpoint
    
    BREAKING CHANGE: The /validate endpoint now returns structured
    validation results instead of boolean. Update client code:
    
    Before:
    - GET /validate?url=<url> { "valid": true }
    
    After:
    - GET /validate?url=<url> { "status": "valid", "issues": [] }
    
    Closes #789

    Multiple Scopes

    feat(core,analytics): integrate embedding generation
    
    Add sentence-transformers support for generating feed embeddings
    with batch processing and caching.

    Body Guidelines

    The body is optional but recommended for:

    • Complex changes requiring explanation
    • Breaking changes (required)
    • Performance impacts
    • Migration instructions

    Format:

    • Separate from header with blank line
    • Wrap at 100 characters
    • Use imperative mood
    • Explain "what" and "why", not "how"

    Footers are optional and used for:

    Issue References

    Closes #123
    Fixes #456, #789
    Relates to #101

    Breaking Changes

    BREAKING CHANGE: <description>

    Deprecations

    DEPRECATED: <what is deprecated and alternative>

    Co-authors

    Co-authored-by: Name <email@example.com>

    Interactive Commits with Commitizen

    For interactive commit creation, use commitizen:

    # Install locally in the workspace if needed
    pnpm add -D commitizen cz-conventional-changelog
    
    # Create commits interactively
    pnpm exec cz

    Commitizen will prompt you for:

    1. Type of change
    2. Scope of change
    3. Short description
    4. Longer description (optional)
    5. Breaking changes (optional)
    6. Issue references (optional)

    Tools Integration

    Pre-commit Hook

    Conventional commits are enforced via pre-commit hook:

    # .pre-commit-config.yaml
    - repo: https://github.com/compilerla/conventional-pre-commit
      rev: v3.0.0
      hooks:
        - id: conventional-pre-commit
          stages: [commit-msg]

    Commitlint

    Validation rules are defined in commitlint.config.js:

    module.exports = {
      extends: ['@commitlint/config-conventional'],
      rules: {
        'type-enum': [2, 'always', ['feat', 'fix', 'docs', ...]],
        'scope-enum': [2, 'always', ['core', 'analytics', ...]],
        'subject-case': [2, 'never', ['sentence-case', 'start-case', ...]],
        'header-max-length': [2, 'always', 100],
      },
    };

    CI/CD Validation

    GitHub Actions validates commits on PRs:

    # .github/workflows/ci.yml
    conventional-commits:
      name: Validate Conventional Commits
      if: github.event_name == 'pull_request'
      steps:
        - name: Validate PR commits
          run: |
            npx commitlint --from ${{ github.event.pull_request.base.sha }} \
                           --to ${{ github.event.pull_request.head.sha }}

    Common Patterns

    Feature Development

    feat(scope): add new capability
    feat(scope): enhance existing feature
    feat(scope): implement X support

    Bug Fixes

    fix(scope): correct incorrect behavior
    fix(scope): handle edge case in X
    fix(scope): prevent Y when Z

    Refactoring

    refactor(scope): simplify X logic
    refactor(scope): extract Y into separate module
    refactor(scope): rename X to Y for clarity

    Performance

    perf(scope): optimize X operation
    perf(scope): cache Y results
    perf(scope): reduce memory usage in Z

    Documentation

    docs(scope): add X documentation
    docs(scope): update Y examples
    docs(scope): clarify Z behavior

    Validation

    Test your commit message format:

    # Test with commitlint
    echo "feat(core): test message" | npx commitlint
    
    # Validate last commit
    npx commitlint --from HEAD~1
    
    # Validate range
    npx commitlint --from HEAD~5 --to HEAD

    Best Practices

    ✅ Good Commits

    feat(analytics): add topic clustering algorithm
    fix(load): handle timeout for slow RSS feeds
    docs(api): add authentication examples
    perf(nlp): optimize embedding batch processing
    test(validate): add schema validation edge cases

    ❌ Bad Commits

    # Too vague
    fix: bug fix
    
    # Not imperative mood
    feat(core): Added new parser
    
    # Capitalized subject
    feat(core): Add new parser
    
    # Period at end
    feat(core): add new parser.
    
    # Missing scope (when appropriate)
    feat: add trending analysis
    
    # Wrong type
    feat(core): fix typo in README

    Changelog Generation

    Conventional commits enable automated changelog generation:

    # Generate changelog
    npx standard-version
    
    # Preview next version
    npx standard-version --dry-run
    
    # First release
    npx standard-version --first-release

    Resources

    FAQ

    Why conventional commits?

    1. Automated Changelog: Generate release notes automatically
    2. Semantic Versioning: Determine version bumps (major/minor/patch)
    3. Clear History: Understand changes at a glance
    4. Better Collaboration: Consistent format across team
    5. Tooling Integration: Enable automation and analysis

    What if I forget the format?

    Use commitizen for interactive prompts:

    npx cz

    Or refer to this guide!

    Can I use multiple scopes?

    Yes, separate with commas:

    feat(core,cli): add new export format

    What about merge commits?

    Merge commits follow the same format:

    Merge pull request #123 from feature-branch
    
    feat(analytics): add trending detection

    How do I indicate breaking changes?

    Three ways:

    1. ! after scope: feat(api)!: redesign endpoint
    2. Footer: BREAKING CHANGE: description
    3. Both (recommended for visibility)

    Support

    For questions or issues with conventional commits:

    Conventional Commits | AI Web Feeds