Contributing
Thank you for your interest in contributing to Agenkit!
Ways to Contribute
There are many ways to contribute:
- Report bugs - Found a bug? Open an issue
- Suggest features - Have an idea? Start a discussion
- Improve docs - Fix typos, add examples, clarify explanations
- Write code - Fix bugs, add features, improve performance
- Share examples - Show us what you've built!
Getting Started
1. Fork and Clone
2. Set Up Development Environment
3. Create a Branch
Development Workflow
1. Make Changes
- Write code following our style guidelines (see below)
- Add tests for new functionality
- Update documentation as needed
2. Run Tests
3. Commit Changes
# Stage changes
git add .
# Commit with descriptive message
git commit -m "feat: add new middleware for X"
Commit message format:
Types:
- feat: New feature
- fix: Bug fix
- docs: Documentation changes
- test: Test additions/changes
- refactor: Code refactoring
- perf: Performance improvements
- chore: Build/tooling changes
4. Push and Create PR
Code Style Guidelines
Python
- PEP 8 compliant - Use
blackfor formatting - Type hints - All public APIs must have type hints
- Docstrings - Use Google-style docstrings
- mypy strict - Code must pass
mypy --strict
from typing import Any
class MyAgent(Agent):
"""
A sample agent that demonstrates style guidelines.
Args:
name: The agent name
config: Optional configuration dict
Example:
>>> agent = MyAgent("my-agent")
>>> response = await agent.process(message)
"""
def __init__(self, name: str, config: dict[str, Any] | None = None):
self._name = name
self._config = config or {}
@property
def name(self) -> str:
"""Agent identifier."""
return self._name
async def process(self, message: Message) -> Message:
"""
Process a message and return a response.
Args:
message: Input message to process
Returns:
Response message
Raises:
ValueError: If message content is invalid
"""
# Implementation here
pass
Go
- gofmt formatted - Always run
gofmt - golangci-lint clean - Must pass linter
- Idiomatic Go - Follow effective Go guidelines
- Comments on exports - All exported items documented
// MyAgent is a sample agent that demonstrates style guidelines.
//
// Example:
//
// agent := &MyAgent{name: "my-agent"}
// response, err := agent.Process(ctx, message)
type MyAgent struct {
name string
config map[string]interface{}
}
// Name returns the agent identifier.
func (a *MyAgent) Name() string {
return a.name
}
// Process processes a message and returns a response.
func (a *MyAgent) Process(ctx context.Context, msg *agenkit.Message) (*agenkit.Message, error) {
// Implementation here
return nil, nil
}
Testing Guidelines
Test Coverage
- New features: Must include tests
- Bug fixes: Must include regression test
- Coverage target: >90% for new code
Test Structure
import pytest
from agenkit import Agent, Message
class TestMyAgent:
"""Tests for MyAgent."""
@pytest.fixture
def agent(self):
"""Create agent instance for testing."""
return MyAgent("test-agent")
@pytest.mark.asyncio
async def test_process_success(self, agent):
"""Test successful message processing."""
message = Message(role="user", content="test")
response = await agent.process(message)
assert response.role == "agent"
assert "test" in response.content
@pytest.mark.asyncio
async def test_process_empty_message(self, agent):
"""Test handling of empty message."""
message = Message(role="user", content="")
with pytest.raises(ValueError):
await agent.process(message)
package mypackage_test
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMyAgent_Process(t *testing.T) {
t.Run("success", func(t *testing.T) {
agent := &MyAgent{name: "test-agent"}
message := &agenkit.Message{
Role: "user",
Content: "test",
}
response, err := agent.Process(context.Background(), message)
require.NoError(t, err)
assert.Equal(t, "agent", response.Role)
assert.Contains(t, response.Content, "test")
})
t.Run("empty_message", func(t *testing.T) {
agent := &MyAgent{name: "test-agent"}
message := &agenkit.Message{Role: "user", Content: ""}
_, err := agent.Process(context.Background(), message)
assert.Error(t, err)
})
}
Documentation Guidelines
- Code comments: Explain WHY, not WHAT
- Docstrings: Required for all public APIs
- Examples: Include usage examples
- Diagrams: Use ASCII art or Mermaid for visuals
Documentation Structure
When updating docs:
# Documentation site
docs-site/
├── getting-started/ # Tutorials and guides
├── core-concepts/ # Architecture and design
├── features/ # Feature documentation
├── guides/ # How-to guides
├── api/ # API reference
└── examples/ # Example code
# Build and preview
mkdocs serve
# Visit http://localhost:8000
Pull Request Process
- Describe your changes
- What does this PR do?
- Why is it needed?
-
How does it work?
-
Link related issues
- Fixes #123
-
Relates to #456
-
Add tests
- New features require tests
-
Existing tests must pass
-
Update documentation
- Add/update docstrings
- Update relevant guides
-
Add examples if applicable
-
Wait for review
- Maintainers will review
- Address feedback
- Keep commits clean
Code Review Checklist
Before requesting review, ensure:
- Tests pass (
pytest tests/orgo test ./...) - Type checking passes (
mypyorgo build) - Linting passes (
ruff,blackorgolangci-lint) - Documentation updated
- Examples added/updated if needed
- Commit messages follow convention
- PR description is clear
Community Guidelines
- Be respectful - Treat everyone with respect
- Be constructive - Focus on the code, not the person
- Be patient - Maintainers are volunteers
- Be open - Consider other perspectives
- Be helpful - Help others when you can
Questions?
- GitHub Discussions: Ask a question
- GitHub Issues: Report a problem
Thank you for contributing to Agenkit! 🎉