Thank you for your interest in contributing to skillkit! This document provides guidelines and instructions for contributing to the project.
- Code of Conduct
- Getting Started
- Development Setup
- Development Workflow
- Testing Guidelines
- Code Style
- Submitting Changes
- Reporting Issues
- Feature Requests
We are committed to providing a welcoming and inclusive environment for all contributors. Please be respectful and constructive in all interactions.
Expected Behavior:
- Be respectful and considerate
- Welcome newcomers and help them get started
- Focus on what is best for the community
- Show empathy towards other community members
Unacceptable Behavior:
- Harassment, discrimination, or offensive comments
- Trolling, insulting, or derogatory remarks
- Public or private harassment
- Publishing others' private information without permission
- Python 3.10 or higher (3.10+ recommended for optimal performance)
- Git
- Basic understanding of Python development
- Familiarity with pytest for testing
- Browse open issues: Check the issue tracker for bugs and feature requests
- Documentation: Help improve documentation, examples, or tutorials
- Bug fixes: Fix bugs and submit pull requests
- New features: Propose and implement new features (discuss first in an issue)
- Tests: Add test coverage for existing functionality
- Examples: Create new example skills or usage patterns
# Fork the repository on GitHub, then clone your fork
git clone https://github.com/YOUR_USERNAME/skillkit.git
cd skillkit# Install package in editable mode with all extras
pip install -e ".[dev,langchain]"This installs:
- Core dependencies (PyYAML)
- Development tools (pytest, pytest-cov, mypy, ruff)
- Optional integrations (langchain-core, pydantic)
# Run tests to ensure everything works
pytest
# Run examples
python examples/basic_usage.py
python examples/langchain_agent.py- Write clear, concise commit messages
- Follow the existing code style
- Add tests for new functionality
- Update documentation as needed
Before committing, ensure all checks pass:
# Run tests with coverage
pytest --cov=src/skillkit --cov-report=html
pytest --cov=src/skillkit --cov-report=term-missing
# Type checking
mypy src/skillkit --strict
# Linting
ruff check src/skillkit
# Format code
ruff format src/skillkitgit add .
git commit -m "Brief description of changes"Commit Message Guidelines:
- Use present tense ("Add feature" not "Added feature")
- Use imperative mood ("Fix bug" not "Fixes bug")
- First line should be 50 characters or less
- Reference issues and PRs when relevant
Examples:
Add async support for skill discovery
Fix YAML parsing error with special characters
Update README with installation instructions
Add tests for argument substitution edge cases
- All new functionality must include tests
- Tests should be in
tests/directory, mirroringsrc/structure - Use pytest fixtures from
tests/conftest.py - Aim for 70%+ code coverage
import pytest
from skillkit import SkillManager
from skillkit.core.exceptions import SkillNotFoundError
def test_feature_success_case(tmp_path):
"""Test successful execution of feature."""
# Arrange
manager = SkillManager(tmp_path)
# Act
result = manager.some_method()
# Assert
assert result is not None
def test_feature_error_case(tmp_path):
"""Test error handling."""
manager = SkillManager(tmp_path)
with pytest.raises(SkillNotFoundError):
manager.invoke_skill("nonexistent")Use pytest markers for categorization:
@pytest.mark.unit # Unit tests
@pytest.mark.integration # Integration tests
@pytest.mark.slow # Slow-running tests# Run specific test file
pytest tests/test_manager.py
# Run specific test
pytest tests/test_manager.py::test_discover_skills
# Run with markers
pytest -m unit
pytest -m "not slow"
# Run with verbose output
pytest -v
# Run with coverage
pytest --cov=src/skillkit --cov-report=html- Follow PEP 8 conventions
- Use type hints for all function signatures
- Maximum line length: 88 characters (Black/Ruff default)
- Use descriptive variable and function names
from pathlib import Path
from typing import Optional, List
def load_skill(
skill_path: Path,
validate: bool = True
) -> Optional[dict[str, str]]:
"""Load a skill from disk.
Args:
skill_path: Path to skill directory
validate: Whether to validate skill contents
Returns:
Skill metadata dictionary or None if loading fails
"""
...- All public functions/classes must have docstrings
- Use Google-style docstrings
- Include examples for complex functionality
def invoke_skill(self, skill_name: str, arguments: str = "") -> str:
"""Invoke a skill with arguments.
Args:
skill_name: Name of skill to invoke
arguments: Arguments to pass to skill
Returns:
Processed skill content with arguments substituted
Raises:
SkillNotFoundError: If skill not found
ContentLoadError: If skill content cannot be loaded
Example:
>>> manager = SkillManager()
>>> manager.discover()
>>> result = manager.invoke_skill("code-reviewer", "Review file.py")
"""
...- Keep functions focused and single-purpose
- Use dataclasses for data structures
- Prefer composition over inheritance
- Follow the existing module structure
git push origin feature/your-feature-name- Go to the skillkit repository
- Click "New Pull Request"
- Select your fork and branch
- Fill out the PR template with:
- Description of changes
- Related issue number (if applicable)
- Testing performed
- Screenshots (if UI-related)
- Maintainers will review your PR
- Address any requested changes
- Once approved, your PR will be merged
- Your contribution will be credited in release notes
Before submitting, ensure:
- All tests pass (
pytest) - Code coverage is maintained or improved
- Type checking passes (
mypy --strict) - Linting passes (
ruff check) - Code is formatted (
ruff format) - Documentation is updated
- Commit messages are clear and descriptive
- Changes are tested on Python 3.10+
When reporting bugs, include:
- Description: Clear description of the issue
- Steps to reproduce: Minimal code example
- Expected behavior: What should happen
- Actual behavior: What actually happens
- Environment:
- Python version
- skillkit version
- Operating system
- Relevant dependencies
Example:
### Bug: Skill discovery fails with spaces in directory names
**Description:**
SkillManager.discover() raises FileNotFoundError when skill directories contain spaces.
**Steps to reproduce:**
```python
from pathlib import Path
from skillkit import SkillManager
# Create skill directory with space
skill_dir = Path("~/.claude/skills/my skill")
skill_dir.mkdir(parents=True)
manager = SkillManager()
manager.discover() # Fails hereExpected: Should discover skills in directories with spaces Actual: FileNotFoundError raised
Environment:
- Python 3.10.19
- skillkit 0.1.0
- macOS 14.0
When proposing features:
- Use case: Describe the problem you're trying to solve
- Proposed solution: How you envision the feature working
- Alternatives considered: Other approaches you've thought about
- Additional context: Examples, mockups, or references
Example:
Use case: In applications with hundreds of skills, synchronous discovery blocks the event loop.
Proposed solution:
Add async def adiscover() method to SkillManager:
manager = SkillManager()
await manager.adiscover()Alternatives:
- Background thread (doesn't work well with async frameworks)
- Lazy discovery (increases latency at invocation time)
Enable debug logging:
import logging
logging.basicConfig(level=logging.DEBUG)Module-specific logging:
logging.getLogger('skillkit.core.discovery').setLevel(logging.DEBUG)Test with many skills:
# Create 100 test skills
python tests/generate_test_skills.py
# Measure discovery time
python -m timeit "from skillkit import SkillManager; m=SkillManager(); m.discover()"from memory_profiler import profile
@profile
def test_memory():
manager = SkillManager()
manager.discover()
# Access content for subset of skills
for skill in manager.list_skills()[:10]:
_ = manager.invoke_skill(skill.name)- Open a discussion
By contributing, you agree that your contributions will be licensed under the MIT License.
Thank you for contributing to skillkit! Your contributions help make AI agents more capable and easier to develop.