Stack-2-9-finetuned / stack /internal /CONTRIBUTING.md
walidsobhie-code
refactor: Squeeze folders further - cleaner structure
65888d5

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

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

  1. Fork the repository on GitHub
  2. 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:

  1. Settings β†’ Project β†’ Python Interpreter β†’ Add β†’ Existing Environment
  2. Select .venv/bin/python
  3. 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 feature
  • fix: Bug fix
  • docs: Documentation changes
  • style: Formatting, missing semicolons, etc.
  • refactor: Code refactoring
  • test: Adding tests
  • chore: 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

  1. 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
  1. Run Linters:
# All linters
make lint

# Individual linters
black --check stack_cli/
flake8 stack_cli/
mypy stack_cli/
  1. Format Code:
# Auto-format code
black stack_cli/

# Sort imports
isort stack_cli/

Pull Request Process

  1. 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"
  1. 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
  1. 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:

  1. Add feature to the features table
  2. Include example usage
  3. Update architecture diagram if needed
  4. 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?


Thank you for contributing to Stack 2.9! πŸŽ‰