Contributing to Stack 2.9
Thank you for your interest in contributing to Stack 2.9! This document provides guidelines and instructions for contributing to the project.
Table of Contents
- Code of Conduct
- Getting Started
- Development Setup
- Code Style
- Making Changes
- Submitting Pull Requests
- Writing Tests
- Documentation Guidelines
- Bug Reports
- Feature Requests
Code of Conduct
By participating in this project, you agree to maintain a respectful and inclusive environment for everyone.
Our Standards:
- Be kind and respectful in all interactions
- Accept constructive criticism gracefully
- Focus on what is best for the community
- Show empathy towards other community members
Unacceptable Behavior:
- Harassment, discrimination, or intimidation
- Personal attacks or derogatory remarks
- Publishing others' private information without permission
- Other conduct that could reasonably be considered inappropriate
Getting Started
Fork the Repository
- Fork the repository on GitHub
- Clone your fork locally:
git clone https://github.com/YOUR_USERNAME/stack-2.9.git
cd stack-2.9
# Add upstream remote
git remote add upstream https://github.com/openclaw/stack-2.9.git
Stay Updated
# Fetch latest changes from upstream
git fetch upstream
# Merge into your main branch
git checkout main
git merge upstream/main
# Update your feature branch
git checkout your-feature-branch
git rebase main
Development Setup
Prerequisites
- Python 3.8+ (3.11+ recommended)
- Node.js 18+ (20 LTS recommended)
- Git
- GPU for model-related testing (optional but recommended)
Environment Setup
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # Linux/macOS
# .venv\Scripts\activate # Windows
# Install dependencies
pip install -r requirements.txt
# Install development dependencies
pip install -e ".[dev]"
# Install pre-commit hooks
pre-commit install
# Install Node.js dependencies (for voice features)
npm install
Verify Installation
# Run tests
pytest
# Check code formatting
make lint
# Run type checking
mypy stack_cli/
IDE Setup
VS Code:
// .vscode/settings.json
{
"python.defaultInterpreterPath": ".venv/bin/python",
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
"python.formatting.provider": "black",
"editor.formatOnSave": true,
"editor.rulers": [100],
"files.exclude": {
"**/__pycache__": true,
"**/*.pyc": true,
".venv": true
}
}
PyCharm:
- Settings β Project β Python Interpreter β Add β Existing Environment
- Select
.venv/bin/python - Enable Black for formatting in Settings β Python β Formatting β Black
Code Style
Python
We follow PEP 8 with some modifications:
- Line length: 100 characters (not 79)
- Use type hints where possible
- Docstrings for all public functions and classes
Style Guide:
"""
Module docstring describing the module's purpose.
"""
from typing import List, Optional, Dict
from dataclasses import dataclass
@dataclass
class ExampleClass:
"""Class docstring describing the class.
Attributes:
name: The name of the example.
value: The value of the example.
"""
name: str
value: int
def __post_init__(self):
"""Validate after initialization."""
if self.value < 0:
raise ValueError("Value must be non-negative")
def process(self, data: List[str]) -> Dict[str, int]:
"""Process data and return results.
Args:
data: List of strings to process.
Returns:
Dictionary mapping strings to their lengths.
Raises:
ValueError: If data is empty.
"""
if not data:
raise ValueError("Data cannot be empty")
return {item: len(item) for item in data}
JavaScript/TypeScript
/**
* Interface for a user configuration.
*/
interface UserConfig {
/** User's display name */
name: string;
/** User's email address */
email: string;
/** Whether the user is enabled */
enabled: boolean;
}
/**
* Process user configuration and return formatted string.
*
* @param config - The user configuration
* @returns Formatted configuration string
*/
export function formatConfig(config: UserConfig): string {
const { name, email, enabled } = config;
if (!enabled) {
return `${name} (disabled)`;
}
return `${name} <${email}>`;
}
Shell Scripts
#!/usr/bin/env bash
set -euo pipefail
# Constant for the application name
readonly APP_NAME="stack-2.9"
readonly LOG_DIR="/var/log/${APP_NAME}"
# Main function
main() {
log "Starting ${APP_NAME}..."
# Implementation here
}
# Logging function
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}
# Run main
main "$@"
Making Changes
Create a Branch
# Start from an updated main branch
git checkout main
git pull upstream main
# Create a new feature branch
git checkout -b feature/your-feature-name
# Or for bug fixes
git checkout -b fix/issue-number-description
# Or for documentation
git checkout -b docs/improvement-description
Branch Naming Conventions
| Type | Pattern | Example |
|---|---|---|
| Feature | feature/<description> |
feature/voice-integration |
| Bug Fix | fix/<issue>-<description> |
fix/123-memory-leak |
| Documentation | docs/<description> |
docs/api-reference |
| Refactoring | refactor/<description> |
refactor/tool-execution |
| Testing | test/<description> |
test/improve-coverage |
Making Commits
# Stage changes
git add path/to/changed/file.py
# Commit with a descriptive message
git commit -m "Add voice cloning support to the tool system
- Added speech_to_text and text_to_speech tools
- Implemented voice_clone tool for custom voice synthesis
- Added voice processing pipeline with Coqui TTS
- Updated documentation with voice examples
Closes: #123"
Commit Message Format
<type>(<scope>): <subject>
<body>
<footer>
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Formatting, missing semicolons, etc.refactor: Code refactoringtest: Adding testschore: Maintenance tasks
Example:
feat(tools): add file search functionality
Implemented fuzzy file search using fzf for quick file discovery.
Added search_files tool that supports:
- Pattern matching with glob
- Fuzzy search with fzf
- File type filtering
Closes: #45
Submitting Pull Requests
Before Submitting
- Run Tests:
# Run all tests
pytest
# Run with coverage
pytest --cov=stack_cli --cov-report=html
# Run specific test file
pytest tests/test_agent.py -v
- Run Linters:
# All linters
make lint
# Individual linters
black --check stack_cli/
flake8 stack_cli/
mypy stack_cli/
- Format Code:
# Auto-format code
black stack_cli/
# Sort imports
isort stack_cli/
Pull Request Process
- Create Pull Request:
# Push your branch
git push origin feature/your-feature-name
# Open PR on GitHub or use CLI
gh pr create --title "Add feature" --body "Description"
- PR Description Template:
## Summary
Brief description of what this PR does.
## Changes Made
- List of specific changes
- Another change
## Motivation
Why is this change needed?
## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests passed
- [ ] Manual testing completed
## Screenshots (if applicable)
## Related Issues
Closes #123
- Review Process:
- Address review comments promptly
- Keep commits atomic and well-described
- Force push to update PR if needed (after reviewers approve)
What We Look For
β
Code that follows our style guidelines
β
Tests that cover the new functionality
β
Documentation updates (if applicable)
β
Clear commit messages
β
No breaking changes (or clearly documented)
β
Performance implications considered
Writing Tests
Test Structure
# tests/test_example.py
"""
Tests for the example module.
"""
import pytest
from unittest.mock import Mock, patch
from stack_cli.example import ExampleClass, process_data
class TestExampleClass:
"""Tests for ExampleClass."""
def setup_method(self):
"""Set up test fixtures."""
self.example = ExampleClass(name="test", value=42)
def test_initialization(self):
"""Test class initialization."""
assert self.example.name == "test"
assert self.example.value == 42
def test_negative_value_raises(self):
"""Test that negative values raise ValueError."""
with pytest.raises(ValueError, match="non-negative"):
ExampleClass(name="test", value=-1)
def test_process_returns_dict(self):
"""Test that process returns expected dictionary."""
result = self.example.process(["hello", "world"])
assert isinstance(result, dict)
assert result["hello"] == 5
assert result["world"] == 5
def test_process_empty_list_raises(self):
"""Test that processing empty list raises ValueError."""
with pytest.raises(ValueError, match="cannot be empty"):
self.example.process([])
class TestProcessData:
"""Tests for process_data function."""
@patch("stack_cli.example.external_service")
def test_calls_external_service(self, mock_service):
"""Test that external service is called correctly."""
mock_service.return_value = {"status": "ok"}
result = process_data(["test"])
mock_service.assert_called_once_with(["test"])
assert result["status"] == "ok"
Test Categories
| Category | Location | Description |
|---|---|---|
| Unit Tests | tests/unit/ |
Test individual functions/classes |
| Integration Tests | tests/integration/ |
Test component interactions |
| API Tests | tests/api/ |
Test API endpoints |
| Tool Tests | tests/tools/ |
Test tool implementations |
| Pattern Memory Tests | tests/self_evolution/ |
Test learning system |
Running Tests
# All tests
pytest
# Specific category
pytest tests/unit/
# With coverage
pytest --cov=stack_cli --cov-report=term-missing --cov-report=html
# Watch mode (auto-run on changes)
ptw # pytest-watch
# Specific test
pytest tests/test_example.py::TestExampleClass::test_initialization -v
Test Fixtures
# conftest.py
import pytest
from pathlib import Path
import tempfile
import shutil
@pytest.fixture
def temp_dir():
"""Create a temporary directory for testing."""
tmpdir = tempfile.mkdtemp()
yield Path(tmpdir)
shutil.rmtree(tmpdir)
@pytest.fixture
def sample_project(temp_dir):
"""Create a sample project structure for testing."""
project = temp_dir / "project"
project.mkdir()
# Create sample files
(project / "main.py").write_text("def main(): pass")
(project / "test.py").write_text("def test(): pass")
return project
@pytest.fixture
def mock_memory():
"""Mock memory system for isolated testing."""
from unittest.mock import MagicMock
memory = MagicMock()
memory.store_memory.return_value = 1
memory.find_similar.return_value = []
return memory
Documentation Guidelines
Docstring Format
We use Sphinx-style docstrings:
def function_name(param1: str, param2: int, param3: Optional[List] = None) -> Dict:
"""Brief description of the function.
Longer description if needed, explaining what the function does,
its purpose, and any important details about its behavior.
Args:
param1: Description of param1.
param2: Description of param2. Must be positive.
param3: Optional description. Defaults to None.
Returns:
Description of the return value. Includes type information.
Raises:
ValueError: When param2 is negative.
TypeError: When param1 is not a string.
Example:
>>> result = function_name("hello", 42)
>>> print(result)
{'param1': 'hello', 'param2': 42}
"""
pass
README Updates
When adding new features, update the README.md:
- Add feature to the features table
- Include example usage
- Update architecture diagram if needed
- Add benchmark results if applicable
API Documentation
For API changes, update API.md:
### Endpoint Name
**Endpoint:** `POST /endpoint`
**Description:** What this endpoint does.
**Request Body:**
```json
{
"field1": "description",
"field2": 123
}
Response:
{
"result": "description"
}
---
## Bug Reports
### Before Submitting a Bug Report
- Search existing issues to avoid duplicates
- Try to reproduce the issue with the latest version
- Gather relevant information:
- Python version
- Stack 2.9 version
- Operating system
- Error message and stack trace
- Steps to reproduce
### Submitting a Bug Report
Use the GitHub issue tracker with the "bug" label:
```markdown
## Bug Description
Clear description of the bug.
## Steps to Reproduce
1. Go to '...'
2. Run '...'
3. See error
## Expected Behavior
What you expected to happen.
## Actual Behavior
What actually happened.
## Environment
- OS: [e.g., Ubuntu 22.04]
- Python: [e.g., 3.11.4]
- Stack 2.9: [e.g., 1.0.0]
## Stack Trace
Full error traceback here
## Additional Context
Any other relevant information.
Feature Requests
Before Submitting a Feature Request
- Search existing issues and PRs
- Consider if the feature aligns with project goals
- Think about implementation approaches
Submitting a Feature Request
## Feature Description
Clear description of the proposed feature.
## Motivation
Why is this feature needed? What problem does it solve?
## Proposed Implementation
How you envision implementing this feature.
## Alternatives Considered
Other approaches you've considered.
## Additional Context
Mockups, diagrams, or other supporting materials.
Recognition
Contributors will be recognized in:
- The project's README acknowledgments section
- Release notes for their contributions
- Our community highlights
Questions?
- GitHub Discussions: Q&A Category
- Discord: Join our community server
- Email: support@stack2.9.openclaw.org
Thank you for contributing to Stack 2.9! π