Skip to main content

Welcome Contributors!

Thank you for your interest in contributing to FastSkill! We welcome contributions of all types, from bug reports and documentation improvements to new features and architectural changes.
FastSkill is a community-driven project. Every contribution, no matter how small, helps make FastSkill better for everyone.

Ways to Contribute

🐛 Bug Reports

  • Report bugs and unexpected behavior
  • Suggest improvements to existing features
  • Help reproduce and verify bug fixes

📚 Documentation

  • Improve existing documentation
  • Add missing examples or tutorials
  • Translate documentation to other languages
  • Create video tutorials or blog posts

💻 Code Contributions

  • Implement new features
  • Fix bugs and security issues
  • Improve performance and reliability
  • Add support for new languages or frameworks

🧪 Testing

  • Write unit and integration tests
  • Test edge cases and error conditions
  • Improve test coverage
  • Create testing utilities and frameworks

🎨 Design and UX

  • Improve user interfaces and experiences
  • Create icons, logos, and visual assets
  • Enhance documentation design
  • Suggest UX improvements

Development Setup

Prerequisites

1

Install Rust

FastSkill’s core is written in Rust for performance:
# Install Rust toolchain
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env

# Verify installation
rustc --version
cargo --version
2

Install Python

For Python bindings and tooling:
# Install Python 3.8+
python --version  # Should be 3.8 or higher

# Install pip if not available
python -m ensurepip --upgrade
3

Install Node.js (optional)

For TypeScript definitions and web tooling:
# Install Node.js 16+
node --version
npm --version

Repository Setup

1

Clone the repository

git clone https://github.com/aroff/fastskill.git
cd fastskill
2

Python development environment

# Set up Python development
cd python
pip install -e ".[dev]"
cd ..

# Verify Python setup
python -c "from fastskill import FastSkillService; print('✅ Python setup complete')"
3

Rust development environment

# Set up Rust development
cd rust
cargo build
cd ..

# Verify Rust setup
cargo test
4

Install development tools

# Python tools
pip install black isort mypy ruff pytest pytest-asyncio

# Rust tools
cargo install cargo-watch cargo-audit cargo-udeps
rustup component add rustfmt clippy

Development Workflow

1. Choose an Issue

1

Find an issue

Browse GitHub Issues and look for:
  • Issues labeled good first issue or help wanted
  • Bugs you can reproduce
  • Features you’d like to implement
  • Documentation improvements
2

Create an issue if needed

If you want to work on something not already tracked:
  • Search existing issues first
  • Create a clear, descriptive issue
  • Include context and expected behavior
  • Tag appropriately (bug, enhancement, documentation)
3

Comment on the issue

Let others know you’re working on it:
I'm interested in working on this issue. I'll start by investigating the problem and creating a reproduction case.

2. Create a Feature Branch

1

Create branch from main

# Create and checkout feature branch
git checkout -b feature/your-feature-name

# Or for bug fixes
git checkout -b fix/issue-description

# Or for documentation
git checkout -b docs/update-guide
2

Branch naming conventions

  • feature/feature-name for new features
  • fix/bug-description for bug fixes
  • docs/section-updates for documentation changes
  • refactor/component-name for code refactoring
  • test/test-description for test improvements

3. Make Your Changes

1

Follow coding standards

  • Python: Follow PEP 8 and use type hints
  • Rust: Follow standard Rust conventions and idioms
  • Documentation: Use clear, concise language with examples
  • Tests: Write comprehensive tests for new functionality
2

Add tests

# Example Python test
import pytest
from fastskill import FastSkillService

@pytest.mark.asyncio
async def test_new_feature():
    service = FastSkillService()
    await service.initialize()

    # Test your new feature
    result = await service.new_feature()
    assert result["success"] == True

    await service.shutdown()
// Example Rust test
#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_new_feature() {
        let service = FastSkillService::new(config).await.unwrap();

        // Test your new feature
        let result = service.new_feature().await.unwrap();
        assert!(result.success);
    }
}
3

Update documentation

  • Add examples for new features
  • Update API documentation
  • Include usage instructions
  • Update changelog if needed

4. Test Your Changes

1

Run tests

# Run all Python tests
python -m pytest python/tests/ -v

# Run Rust tests
cargo test

# Run integration tests
python -m pytest python/tests/ -k integration

# Run specific test
python -m pytest python/tests/test_specific_feature.py -v
2

Test manually

# Manual testing in Python
import asyncio
from fastskill import FastSkillService

async def manual_test():
    service = FastSkillService()
    await service.initialize()

    # Test your changes
    result = await your_new_function()
    print(f"Result: {result}")

    await service.shutdown()

asyncio.run(manual_test())
3

Check code quality

# Python code quality
black src/ tests/          # Format code
isort src/ tests/          # Sort imports
mypy src/                  # Type checking
ruff check src/ tests/     # Linting

# Rust code quality
cargo fmt --check          # Check formatting
cargo clippy -- -D warnings # Linting
cargo audit                # Security audit

5. Submit Your Contribution

1

Commit your changes

# Stage your changes
git add .

# Commit with descriptive message
git commit -m "feat: add new feature description

- Add support for X functionality
- Include comprehensive tests
- Update documentation with examples

Resolves #123"
2

Commit message format

type: description

- Additional details
- More context if needed
- Issue references

Resolves #123
Types:
  • feat: New feature
  • fix: Bug fix
  • docs: Documentation changes
  • test: Test improvements
  • refactor: Code refactoring
  • chore: Maintenance tasks
3

Push your branch

git push origin feature/your-feature-name
4

Create pull request

  1. Go to the repository on GitHub
  2. Click “Compare & pull request”
  3. Fill out the pull request template
  4. Add appropriate labels
  5. Request review from maintainers

Code Standards

Python Standards

import asyncio
from typing import Dict, List, Optional
from pathlib import Path

from fastskill import FastSkillService, ServiceConfig


async def process_skills(skill_ids: List[str]) -> Dict[str, Dict]:
    """Process multiple skills concurrently.

    Args:
        skill_ids: List of skill identifiers

    Returns:
        Dictionary mapping skill IDs to processing results
    """
    service = FastSkillService()
    await service.initialize()

    try:
        # Use asyncio.gather for concurrent processing
        tasks = [process_single_skill(service, skill_id) for skill_id in skill_ids]
        results = await asyncio.gather(*tasks, return_exceptions=True)

        # Handle both successful results and exceptions
        processed_results = {}
        for skill_id, result in zip(skill_ids, results):
            if isinstance(result, Exception):
                processed_results[skill_id] = {"error": str(result)}
            else:
                processed_results[skill_id] = result

        return processed_results

    finally:
        await service.shutdown()


async def process_single_skill(service: FastSkillService, skill_id: str) -> Dict:
    """Process a single skill."""
    try:
        # Validate input
        if not skill_id:
            raise ValueError("Skill ID cannot be empty")

        # Get skill information
        skill = await service.get_skill(skill_id)
        if not skill:
            raise ValueError(f"Skill not found: {skill_id}")

        # Process skill (implementation details)
        return {"status": "processed", "skill_id": skill_id}

    except Exception as e:
        # Log error for debugging
        logger.error(f"Error processing skill {skill_id}: {e}")
        raise

Rust Standards

use std::collections::HashMap;
use tokio::sync::RwLock;
use anyhow::{Context, Result};

pub struct SkillProcessor {
    service: Arc<FastSkillService>,
    cache: Arc<RwLock<HashMap<String, ProcessedSkill>>>,
}

impl SkillProcessor {
    pub fn new(service: Arc<FastSkillService>) -> Self {
        Self {
            service,
            cache: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    pub async fn process_skills(&self, skill_ids: &[String]) -> Result<HashMap<String, ProcessedSkill>> {
        let mut results = HashMap::new();

        // Process concurrently with controlled parallelism
        let semaphore = Arc::new(Semaphore::new(10)); // Max 10 concurrent

        let tasks: Vec<_> = skill_ids
            .iter()
            .map(|skill_id| {
                let service = Arc::clone(&self.service);
                let semaphore = Arc::clone(&semaphore);
                let skill_id = skill_id.clone();

                tokio::spawn(async move {
                    let _permit = semaphore.acquire().await
                        .context("Failed to acquire semaphore permit")?;

                    Self::process_single_skill(service, &skill_id).await
                })
            })
            .collect();

        // Wait for all tasks and collect results
        for (skill_id, task) in skill_ids.iter().zip(tasks) {
            match task.await {
                Ok(Ok(result)) => {
                    results.insert(skill_id.clone(), result);
                }
                Ok(Err(e)) => {
                    log::error!("Error processing skill {}: {}", skill_id, e);
                    results.insert(skill_id.clone(), ProcessedSkill::error(e));
                }
                Err(e) => {
                    log::error!("Task panicked for skill {}: {}", skill_id, e);
                    results.insert(skill_id.clone(), ProcessedSkill::error(
                        anyhow::Error::msg("Task panicked")));
                }
            }
        }

        Ok(results)
    }

    async fn process_single_skill(
        service: Arc<FastSkillService>,
        skill_id: &str,
    ) -> Result<ProcessedSkill> {
        // Validate input
        if skill_id.is_empty() {
            anyhow::bail!("Skill ID cannot be empty");
        }

        // Check cache first
        if let Some(cached) = self.cache.read().await.get(skill_id) {
            return Ok(cached.clone());
        }

        // Get and process skill
        let skill = service.get_skill(skill_id)
            .await
            .context("Failed to get skill")?
            .context("Skill not found")?;

        let processed = ProcessedSkill {
            skill_id: skill_id.to_string(),
            status: ProcessingStatus::Completed,
            processed_at: chrono::Utc::now(),
            data: process_skill_data(&skill),
        };

        // Cache the result
        self.cache.write().await.insert(skill_id.to_string(), processed.clone());

        Ok(processed)
    }
}

#[derive(Debug, Clone)]
pub struct ProcessedSkill {
    pub skill_id: String,
    pub status: ProcessingStatus,
    pub processed_at: chrono::DateTime<chrono::Utc>,
    pub data: serde_json::Value,
}

impl ProcessedSkill {
    pub fn error(error: anyhow::Error) -> Self {
        Self {
            skill_id: String::new(),
            status: ProcessingStatus::Failed,
            processed_at: chrono::Utc::now(),
            data: serde_json::json!({"error": error.to_string()}),
        }
    }
}

#[derive(Debug, Clone)]
pub enum ProcessingStatus {
    Completed,
    Failed,
    InProgress,
}

Testing Guidelines

Test Structure

1

Unit tests

Test individual functions and methods in isolation:
# python/tests/test_skill_manager.py
import pytest
from fastskill.skill_manager import SkillManager

class TestSkillManager:
    @pytest.fixture
    def skill_manager(self):
        return SkillManager()

    def test_register_skill_valid(self, skill_manager):
        skill_data = {
            "id": "test-skill",
            "name": "Test Skill",
            "description": "A test skill",
            "version": "1.0.0"
        }

        skill_id = skill_manager.register_skill(skill_data)
        assert skill_id == "test-skill"

    def test_register_skill_duplicate(self, skill_manager):
        skill_data = {"id": "duplicate", "name": "Test", "version": "1.0.0"}

        # First registration should succeed
        skill_manager.register_skill(skill_data)

        # Second registration should fail
        with pytest.raises(ValueError, match="already exists"):
            skill_manager.register_skill(skill_data)
2

Integration tests

Test component interactions:
# python/tests/test_integration.py
import pytest
import asyncio
from fastskill import FastSkillService

@pytest.mark.asyncio
class TestIntegration:
    async def test_full_workflow(self):
        """Test complete skill registration and discovery workflow."""
        service = FastSkillService()
        await service.initialize()

        # Register skill
        skill_id = await service.register_skill({
            "id": "integration-test-skill",
            "name": "Integration Test Skill",
            "description": "Used for integration testing",
            "version": "1.0.0",
            "tags": ["test", "integration"],
            "capabilities": ["testing"]
        })

        # Test discovery
        skills = await service.discover_skills("integration testing")
        assert len(skills) > 0
        assert skills[0]["id"] == skill_id

        # Test capability search
        test_skills = await service.find_skills_by_capability("testing")
        assert len(test_skills) > 0

        # Cleanup
        await service.delete_skill(skill_id)
        await service.shutdown()
3

Performance tests

Test performance characteristics:
# python/tests/test_performance.py
import pytest
import asyncio
import time
from fastskill import FastSkillService

@pytest.mark.asyncio
@pytest.mark.performance
class TestPerformance:
    async def test_skill_discovery_performance(self):
        """Test that skill discovery meets performance requirements."""
        service = FastSkillService()
        await service.initialize()

        # Register multiple skills for testing
        for i in range(100):
            await service.register_skill({
                "id": f"perf-test-skill-{i}",
                "name": f"Performance Test Skill {i}",
                "description": f"Test skill {i} for performance testing",
                "version": "1.0.0",
                "tags": ["performance", "test"],
                "capabilities": ["testing"]
            })

        # Measure discovery performance
        start_time = time.time()

        skills = await service.discover_skills("performance testing")

        end_time = time.time()
        duration = end_time - start_time

        # Assert performance requirements
        assert len(skills) == 100
        assert duration < 1.0  # Should complete in under 1 second

        await service.shutdown()

Test Coverage

1

Run coverage analysis

# Python coverage
pip install coverage
coverage run -m pytest python/tests/
coverage report --fail-under=90  # Require 90% coverage
coverage html  # Generate HTML report

# Rust coverage (with tarpaulin)
cargo install cargo-tarpaulin
cargo tarpaulin --out html
2

Check coverage requirements

  • Minimum 90% code coverage for new code
  • 100% coverage for critical paths
  • Test edge cases and error conditions
  • Test both success and failure scenarios

Documentation Standards

Writing Guidelines

1

Use clear language

  • Write in second person (“you”) for instructions
  • Use active voice
  • Keep sentences concise but informative
  • Avoid jargon or define it when used
2

Structure content well

  • Use descriptive headings
  • Include code examples for technical content
  • Provide step-by-step instructions for procedures
  • Include troubleshooting sections
3

API documentation

# Include comprehensive API documentation
def register_skill(self, skill_definition: Dict[str, Any]) -> str:
    """Register a new skill with the FastSkill service.

    This method validates the skill definition, stores it in the
    skill repository, and makes it available for discovery and execution.

    Args:
        skill_definition: Complete skill definition including metadata,
            capabilities, and implementation details. Must include required
            fields: id, name, description, version.

    Returns:
        The unique identifier of the registered skill.

    Raises:
        ValidationError: If the skill definition is invalid or incomplete.
        DuplicateSkillError: If a skill with the same ID already exists.
        StorageError: If the skill cannot be stored due to system issues.

    Example:
        >>> skill_id = await service.register_skill({
        ...     "id": "text-processor",
        ...     "name": "Text Processor",
        ...     "description": "Process text documents",
        ...     "version": "1.0.0"
        ... })
        >>> print(skill_id)
        'text-processor'
    """
    pass

Pull Request Process

PR Requirements

1

Fill out the PR template

  • Description: What the PR does and why
  • Related Issues: Links to related issues
  • Testing: How you tested the changes
  • Breaking Changes: Any backward compatibility issues
  • Documentation: Documentation updates included
2

Include tests

Every PR must include appropriate tests:
  • Unit tests for new functionality
  • Integration tests for component interactions
  • Regression tests for bug fixes
  • Performance tests for performance changes
3

Update documentation

  • Add examples for new features
  • Update API documentation
  • Include usage instructions
  • Update changelog if needed

Review Process

1

Automated checks

All PRs run automated checks:
  • Code formatting (black, rustfmt)
  • Linting (ruff, clippy)
  • Type checking (mypy)
  • Security scanning (cargo audit)
  • Test suite execution
2

Maintainer review

Maintainers will review your PR for:
  • Code quality and style
  • Test coverage
  • Documentation completeness
  • Backward compatibility
  • Security implications
3

Address feedback

  • Respond to all review comments
  • Make requested changes
  • Ask for clarification if needed
  • Update PR description if scope changes

Community Guidelines

Communication

1

Be respectful

  • Treat all contributors with respect
  • Use inclusive language
  • Give constructive feedback
  • Accept feedback gracefully
2

Be collaborative

  • Help other contributors
  • Share knowledge and resources
  • Work together on solutions
  • Acknowledge others’ contributions
3

Stay on topic

  • Keep discussions focused on FastSkill
  • Use appropriate channels for different topics
  • Avoid off-topic conversations

Contribution Recognition

1

Contributors are recognized

  • Contributors are listed in the README
  • Major contributors may be invited to become maintainers
  • Contributions are highlighted in release notes
  • Community contributions are celebrated
2

Quality over quantity

  • We value well-tested, well-documented contributions
  • Small, focused changes are preferred over large, complex ones
  • Clear, readable code is more important than clever code

Getting Help

As a Contributor

1

Ask questions

Don’t hesitate to ask questions:
  • Use GitHub Discussions for general questions
  • Ask in PR comments for specific feedback
  • Join community chat for real-time help
2

Request reviews

  • Ask for early feedback on complex changes
  • Request review from specific maintainers if needed
  • Provide context for your changes
3

Learn from feedback

  • Review comments are meant to help improve the codebase
  • Ask for clarification if something is unclear
  • Apply feedback consistently across your changes

Code License

All contributions to FastSkill are licensed under the project license (MIT OR Apache-2.0). By contributing, you agree that your contributions can be used under these license terms.
  • Don’t include copyrighted code without permission
  • Respect trademarks and branding
  • Attribute third-party code appropriately
  • Follow open source licensing requirements
Ensure all your contributions are your original work or properly licensed third-party code. Maintainers may remove contributions that violate copyright or licensing terms.

Recognition and Rewards

Contribution Badges

Contributors earn recognition badges:
  • First Contribution: Welcome badge for first-time contributors
  • Bug Hunter: For reporting and fixing bugs
  • Documentation Hero: For improving documentation
  • Feature Developer: For implementing new features
  • Test Champion: For improving test coverage
  • Community Helper: For helping other contributors

Hall of Fame

Major contributors are recognized in:
  • README contributors section
  • Release notes
  • Community highlights
  • Project governance (for consistent contributors)
Thank you for contributing to FastSkill! Your contributions help make AI agent development more accessible and powerful for developers worldwide.