Thank you for your interest in contributing! This project provides validators, parsers, and analysis tools specifically designed to save AI agents' tokens.
✅ v0.9.1 Released: 286 functions across 8 core modules + 7 language-specific modules
- 83% test coverage, 571 tests passing
- 100% ruff/mypy compliance
- All modules use
@strands_tooldecorator
See CHANGELOG.md for release history and TODO.md for roadmap.
- Python 3.9 or higher
- Git
- (Optional) UV, Poetry, or another Python package manager
-
Fork and clone the repository
git clone https://github.com/YOUR_USERNAME/coding-open-agent-tools.git cd coding-open-agent-tools -
Create a virtual environment
python -m venv .venv source .venv/bin/activate # On Windows: .venv\Scripts\activate
-
Install development dependencies
pip install -e ".[dev]" -
Install pre-commit hooks (optional but recommended)
pre-commit install
-
Verify installation
# Run tests pytest tests/ # Run quality checks ruff check . mypy src/
git checkout -b feature/your-feature-name
# or
git checkout -b fix/bug-descriptionFollow the coding standards (see below) and write tests for new functionality.
Before committing, always run:
# Auto-fix linting issues
ruff check . --fix
ruff format .
# Type checking
mypy src/
# Run tests
pytest tests/
# Run tests with coverage
pytest tests/ --cov=src --cov-report=termFollow conventional commit format:
git add .
git commit -m "feat: add new functionality"Commit Types:
feat:- New featurefix:- Bug fixdocs:- Documentation changestest:- Adding/updating testsrefactor:- Code refactoringchore:- Maintenance tasksperf:- Performance improvements
git push origin feature/your-feature-nameThen create a pull request on GitHub with:
- Clear description of changes
- Reference to related issues
- Examples if applicable
- ✅ 100% ruff compliance - No exceptions
- ✅ 100% mypy compliance - Full type coverage
- ✅ 80%+ test coverage - Every function tested
- ✅ Google ADK compliance - JSON-serializable returns, no defaults
- ✅ Proper decorators - All tools must use
@strands_tool - ✅ Comprehensive docstrings - Help LLMs understand function purpose
All agent tools MUST use the @strands_tool decorator with conditional import:
from coding_open_agent_tools._decorators import strands_tool
@strands_tool
def your_function(param1: str, param2: str) -> dict[str, str]:
"""Brief description.
Detailed explanation of what the function does and why it exists.
Explain the token savings rationale.
Args:
param1: Description of param1
param2: Description of param2
Returns:
Dictionary with:
- key1: Description
- key2: Description
Raises:
TypeError: If parameters are not strings
ValueError: If parameters are empty or invalid
FileNotFoundError: If file does not exist (if applicable)
Examples:
>>> result = your_function("value1", "value2")
>>> print(result["key1"])
'expected_value'
"""
# Validate inputs
if not isinstance(param1, str):
raise TypeError("param1 must be a string")
if not param1.strip():
raise ValueError("param1 cannot be empty")
# Implementation
...
# Return JSON-serializable dict
return {
"key1": "value1",
"key2": "value2",
"error": "",
}All functions MUST follow these rules:
-
JSON-serializable types only
- ✅ Use:
str,int,float,bool,dict,list - ❌ Avoid:
bytes,Union,Optional,Any, custom classes
- ✅ Use:
-
Typed collections
- ✅ Use:
list[dict[str, str]],dict[str, str] - ❌ Avoid: bare
list, baredict
- ✅ Use:
-
No default parameters
- ❌
def func(param: str = "default")- NOT ALLOWED - ✅
def func(param: str)- Required parameter
- ❌
-
String returns for all primitives
- Return
{"count": "42", "is_valid": "true"}not{"count": 42, "is_valid": True} - Agents can easily parse string values
- Return
-
Comprehensive docstrings
- Include Args, Returns, Raises, Examples
- Explain token savings rationale
- Help LLMs understand when to use the function
Always validate inputs with clear error messages:
@strands_tool
def analyze_code(file_path: str, threshold: str) -> dict[str, str]:
"""Analyze code complexity."""
# Type validation
if not isinstance(file_path, str):
raise TypeError("file_path must be a string")
if not isinstance(threshold, str):
raise TypeError("threshold must be a string")
# Value validation
if not file_path.strip():
raise ValueError("file_path cannot be empty")
# Numeric validation (when string represents number)
try:
threshold_int = int(threshold)
if threshold_int < 0:
raise ValueError("threshold must be non-negative")
except ValueError as e:
raise ValueError(f"threshold must be a valid integer: {e}")
# File existence validation
if not os.path.exists(file_path):
raise FileNotFoundError(f"File not found: {file_path}")
# Implementation
passtests/
├── [module]/
│ ├── test_[submodule].py
│ └── ...
1. Type Validation Tests
def test_invalid_param_type(self) -> None:
"""Test TypeError when param is not a string."""
with pytest.raises(TypeError, match="param must be a string"):
function_name(123, "valid") # type: ignore2. Value Validation Tests
def test_empty_param(self) -> None:
"""Test ValueError when param is empty."""
with pytest.raises(ValueError, match="param cannot be empty"):
function_name("", "valid")3. Path Validation Tests
def test_file_not_found(self, tmp_path: Path) -> None:
"""Test FileNotFoundError for missing file."""
nonexistent = tmp_path / "missing.py"
with pytest.raises(FileNotFoundError):
function_name(str(nonexistent))4. Happy Path Tests
def test_success_case(self) -> None:
"""Test successful operation."""
result = function_name("valid_input", "valid_param")
assert result["success"] == "true"
assert result["error"] == ""
assert "expected_key" in result5. Edge Case Tests
def test_edge_case_empty_result(self) -> None:
"""Test handling of empty result."""
result = function_name("input_with_no_matches")
assert result["count"] == "0"
assert result["items"] == "[]"6. Mocked Subprocess Tests (for git/shell operations)
@patch("subprocess.run")
def test_git_command(self, mock_run: MagicMock) -> None:
"""Test git command execution."""
mock_run.return_value = MagicMock(
returncode=0,
stdout="mocked output",
stderr=""
)
result = git_function("/path/to/repo")
assert result["success"] == "true"
mock_run.assert_called_once()# Run all tests
pytest
# Run specific test file
pytest tests/git/test_health.py
# Run with coverage
pytest --cov=src/coding_open_agent_tools
# Run with verbose output
pytest -v
# Run tests matching pattern
pytest -k "test_validation"
# Run fast tests only (skip slow)
pytest -m "not slow"- Overall: 80%+ coverage
- Critical modules: 90%+ coverage
- New code: 80%+ coverage minimum
-
Validators - Catch errors before execution
- Syntax validation (shell, Python, YAML, JSON)
- Type hint validation
- Schema validation
-
Parsers - Convert unstructured → structured
- Tool output parsing (ruff, mypy, pytest, git)
- Log parsing and extraction
- Configuration file parsing
-
Extractors - Pull specific data
- Function signatures
- Docstring information
- Import statements
- Complexity metrics
-
Formatters - Apply deterministic rules
- Argument escaping (shell, SQL)
- Import sorting
- Docstring formatting
-
Scanners - Rule-based detection
- Secret detection
- Security anti-patterns
- Performance anti-patterns
- Compliance checking
-
Bug fixes - Fix existing issues
-
Tests - Improve test coverage
-
Documentation - Improve examples and guides
- Code generators - Agents excel at creative logic
- Architecture tools - Requires judgment and context
- Opinionated refactoring - Agents handle transformations
- External binary dependencies - Prefer stdlib
- Duplicate functionality - Check existing modules first
When adding a new function, ask:
- It's deterministic (same input → same output)
- Agents waste tokens on it (>100 tokens for trivial task)
- It prevents errors (syntax, security, type)
- It converts unstructured → structured
- It's tedious for agents (parsing, escaping, formatting)
- Agents already do it well (creative logic, architecture)
- It requires judgment or context
- It's code generation (unless tiny formatters/escapers)
- It duplicates existing tools
- It would add external dependencies without strong justification
When adding new modules, follow the established structure:
src/coding_open_agent_tools/
├── [module_name]/
│ ├── __init__.py # Export public functions
│ ├── validators.py # Validation functions
│ ├── parsers.py # Parsing functions
│ ├── analyzers.py # Analysis functions
│ ├── extractors.py # Data extraction
│ ├── formatters.py # Formatting functions
│ └── utils.py # Helper utilities
- ✅ All tests pass
- ✅ Code coverage meets minimum (80%+)
- ✅ Ruff and mypy pass with no errors
- ✅ Documentation is updated
- ✅ Examples added (if applicable)
- ✅ CHANGELOG.md updated (for significant changes)
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Related Issues
Fixes #(issue number)
## Token Savings
Explain how this change saves agent tokens (if applicable)
## Testing
Describe the tests you added/updated
## Checklist
- [ ] Tests pass locally
- [ ] Code coverage >= 80%
- [ ] Ruff/mypy compliance
- [ ] Documentation updated
- [ ] Examples added (if new feature)- Automated checks run on all PRs
- Maintainer review for code quality and design
- Test coverage verification
- Documentation review
- Merge when approved
When adding optional dependencies:
- It provides substantial value (10x better than stdlib)
- It's pip-installable Python library (not external binary)
- There's graceful fallback to stdlib
- It's actively maintained (1000+ stars, recent commits)
- It's Python-native (can import, not subprocess-only)
- Stdlib solution is "good enough" (80% as good)
- It's a Go/Rust binary requiring subprocess
- No graceful fallback possible
- Maintenance concerns (unmaintained, <500 stars)
- Only marginal improvement over stdlib
def enhanced_function(
content: str,
use_enhancement: str # "true" or "false" (ADK compliance)
) -> dict[str, str]:
"""Function with optional enhanced functionality.
Falls back to stdlib if enhancement not installed.
"""
if use_enhancement == "true":
try:
from optional_package import enhanced_feature
return _enhanced_implementation(content)
except ImportError:
# Graceful fallback to stdlib
return _stdlib_implementation(content)
else:
return _stdlib_implementation(content)When adding features, update:
- README.md - If adding new module or major feature
- ARCHITECTURE.md - If changing design patterns
- docs/examples/ - Add practical examples
- Docstrings - Comprehensive function documentation
- CHANGELOG.md - Document all changes
This project follows the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code.
- Open an issue for bug reports or feature requests
- Start a discussion for design questions
- Check existing issues before creating new ones
- Review docs/examples/ for usage patterns
By contributing, you agree that your contributions will be licensed under the MIT License.
Key Mantras:
- Parse, don't generate
- Validate early, save tokens
- Deterministic operations only
- If agents do it well, skip it
- Prevent errors > Generate code
When in doubt, ask: "Does this save agent tokens or prevent retry loops?"
If no, it probably doesn't belong here.