Contributing Guide
Guide for contributing to the NorthBuilt RAG System.
Welcome
Thank you for considering contributing to the NorthBuilt RAG System! This guide will help you understand our development process and how to submit changes.
Table of Contents
- Code of Conduct
- Getting Started
- Development Workflow
- Coding Standards
- Testing
- Pull Request Process
- Release Process
Code of Conduct
Our Standards
- Be respectful and inclusive
- Welcome newcomers and help them get started
- Focus on what is best for the project
- Show empathy towards other community members
- Accept constructive criticism gracefully
Unacceptable Behavior
- Trolling, insulting/derogatory comments, and personal attacks
- Public or private harassment
- Publishing others’ private information without permission
- Other conduct which could reasonably be considered inappropriate
Getting Started
Prerequisites
Before contributing, ensure you have:
- AWS account with appropriate permissions
- AWS CLI configured
- Terraform installed (>= 1.13.0)
- Python 3.13+ installed
- Git installed
- GitHub account
- GitHub CLI (
gh) installed
See Initial Setup Guide for detailed setup instructions.
Repository Setup
# 1. Fork the repository
gh repo fork craftcodery/compass --clone
# 2. Navigate to directory
cd compass
# 3. Add upstream remote
git remote add upstream https://github.com/craftcodery/compass.git
# 4. Verify remotes
git remote -v
# origin https://github.com/YOUR_USERNAME/compass.git (fetch)
# origin https://github.com/YOUR_USERNAME/compass.git (push)
# upstream https://github.com/craftcodery/compass.git (fetch)
# upstream https://github.com/craftcodery/compass.git (push)
First Contribution
Look for issues labeled good first issue or help wanted:
gh issue list --label "good first issue"
Development Workflow
Branch Strategy
We use a simplified GitHub Flow strategy:
main (production)
├── feature/add-new-integration
├── fix/lambda-timeout-issue
└── docs/improve-setup-guide
Branch Naming:
feature/- New featuresfix/- Bug fixesdocs/- Documentation changesrefactor/- Code refactoringtest/- Test additions/changes
Creating a Branch
# 1. Ensure main is up to date
git checkout main
git pull upstream main
# 2. Create feature branch
git checkout -b feature/your-feature-name
# 3. Make changes
# ... edit files ...
# 4. Commit changes (see commit guidelines below)
git add .
git commit -m "feat: add new integration for Slack"
# 5. Push to your fork
git push origin feature/your-feature-name
# 6. Create pull request
gh pr create --base main --head feature/your-feature-name
Syncing Your Fork
# Fetch upstream changes
git fetch upstream
# Merge upstream main into your main
git checkout main
git merge upstream/main
# Push to your fork
git push origin main
# Update feature branch (if needed)
git checkout feature/your-feature-name
git rebase main
Coding Standards
Python Style Guide
We follow PEP 8 with some modifications:
# File: lambda/example/handler.py
"""
Lambda function handler for example functionality.
"""
import json
import logging
from typing import Dict, Any, List, Optional
# Configure logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
"""
Handle Lambda invocation.
Args:
event: Lambda event object
context: Lambda context object
Returns:
API Gateway response object
"""
try:
# Log request
logger.info(f"Processing request: {json.dumps(event)}")
# Extract parameters
body = json.loads(event.get('body', '{}'))
query = body.get('query')
# Validate input
if not query:
return {
'statusCode': 400,
'body': json.dumps({'error': 'Missing query parameter'})
}
# Process request
result = process_query(query)
# Return response
return {
'statusCode': 200,
'body': json.dumps(result)
}
except Exception as e:
logger.error(f"Error processing request: {str(e)}", exc_info=True)
return {
'statusCode': 500,
'body': json.dumps({'error': 'Internal server error'})
}
def process_query(query: str) -> Dict[str, Any]:
"""
Process user query.
Args:
query: User query string
Returns:
Query result dictionary
"""
# Implementation
return {'answer': 'Result', 'sources': []}
Key Points:
- Use type hints for function parameters and return values
- Document all functions with docstrings (Google style)
- Maximum line length: 100 characters
- Use meaningful variable names
- Handle exceptions appropriately
- Log important events
Terraform Style Guide
# File: terraform/modules/example/main.tf
# Lambda function
resource "aws_lambda_function" "example" {
function_name = "${var.project_prefix}-example"
role = aws_iam_role.example.arn
handler = "handler.lambda_handler"
runtime = "python3.13"
timeout = 30
memory_size = 512
filename = data.archive_file.example.output_path
source_code_hash = data.archive_file.example.output_base64sha256
environment {
variables = {
LOG_LEVEL = var.log_level
REGION = var.region
}
}
tracing_config {
mode = "Active"
}
tags = {
Component = "compute"
}
}
# IAM role
resource "aws_iam_role" "example" {
name = "${var.project_prefix}-example-lambda-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
}
]
})
tags = {
Component = "iam"
}
}
Key Points:
- Use 2-space indentation
- Group related resources together
- Use variables for reusable values
- Add comments for complex resources
- Always add tags
- Format code:
terraform fmt -recursive
TypeScript/React Style Guide
// File: web/src/lib/api.ts
/**
* Handle chat message submission
* @param message - User message
* @param token - Authentication token
* @returns Promise resolving to chat response
*/
export async function sendMessage(
message: string,
token: string
): Promise<ChatResponse> {
// Validate input
if (!message?.trim()) {
throw new Error('Message cannot be empty');
}
if (!token) {
throw new Error('Not authenticated');
}
try {
// Send request
const response = await fetch(`${API_URL}/chat`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: message,
max_results: 5
})
});
// Handle errors
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || 'Request failed');
}
// Parse and return typed response
return await response.json() as ChatResponse;
} catch (error) {
console.error('Error sending message:', error);
throw error;
}
}
Key Points:
- Use TypeScript with proper type annotations
- Use modern React patterns (hooks, functional components)
- Follow the existing code structure and naming conventions
- Use
constandlet, notvar - Handle errors appropriately
- Export functions explicitly
Code Formatting
# Python (using black)
pip3 install black
black lambda/
# Terraform
terraform fmt -recursive
# TypeScript/React (using ESLint and built-in formatter)
cd web
npm run lint
npm run format # if available, or use built-in editor formatting
Testing
Testing Strategy
- Unit Tests: Test individual functions in isolation
- Integration Tests: Test Lambda functions with mocked AWS services
- End-to-End Tests: Test full API flow (manual or automated)
Python Unit Tests
# File: lambda/chat/test_handler.py
import unittest
from unittest.mock import Mock, patch
from handler import lambda_handler, process_query
class TestChatHandler(unittest.TestCase):
"""Test chat Lambda handler"""
def setUp(self):
"""Set up test fixtures"""
self.sample_event = {
'body': '{"query": "What is this system?"}',
'requestContext': {
'authorizer': {
'claims': {
'sub': 'user-123'
}
}
}
}
self.sample_context = Mock()
def test_lambda_handler_success(self):
"""Test successful Lambda invocation"""
with patch('handler.process_query') as mock_process:
mock_process.return_value = {
'answer': 'Test answer',
'sources': []
}
response = lambda_handler(self.sample_event, self.sample_context)
self.assertEqual(response['statusCode'], 200)
body = json.loads(response['body'])
self.assertEqual(body['answer'], 'Test answer')
def test_lambda_handler_missing_query(self):
"""Test Lambda with missing query parameter"""
event = {'body': '{}'}
response = lambda_handler(event, self.sample_context)
self.assertEqual(response['statusCode'], 400)
body = json.loads(response['body'])
self.assertIn('error', body)
if __name__ == '__main__':
unittest.main()
Running Tests:
# Run unit tests
cd lambda/chat
python3 -m pytest test_handler.py -v
# Run with coverage
python3 -m pytest --cov=handler --cov-report=html
Terraform Tests
# Validate Terraform configuration
cd terraform
terraform validate
# Check formatting
terraform fmt -check -recursive
# Plan without applying
terraform plan
# Run terraform tests (if available)
terraform test
Manual Testing
# Test Lambda function locally (AWS SAM)
sam local invoke ChatFunction -e events/sample-event.json
# Test API endpoint
curl -X POST https://[api-url]/chat \
-H "Authorization: Bearer [jwt-token]" \
-H "Content-Type: application/json" \
-d '{"query": "test query"}'
# Test webhook
curl -X POST https://[api-url]/webhooks/fathom \
-H "x-api-key: [api-key]" \
-H "Content-Type: application/json" \
-d '{"event": "test"}'
Pull Request Process
Before Submitting
- Code follows style guidelines
- Tests pass locally
- Documentation updated (if needed)
- Commit messages follow convention
- Branch is up to date with main
- No merge conflicts
Commit Message Convention
We use Conventional Commits format:
<type>(<scope>): <subject>
<body>
<footer>
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, etc.)refactor: Code refactoringtest: Test changeschore: Build process or tooling changes
Examples:
# Feature commit
git commit -m "feat(lambda): add Slack webhook integration"
# Bug fix commit
git commit -m "fix(auth): resolve Cognito redirect URI mismatch"
# Documentation commit
git commit -m "docs(setup): add Knowledge Base configuration steps"
# Breaking change commit
git commit -m "feat(api): change chat endpoint response format
BREAKING CHANGE: Response now includes pagination metadata"
Creating a Pull Request
# 1. Push branch to your fork
git push origin feature/your-feature-name
# 2. Create PR via GitHub CLI
gh pr create \
--title "feat: add Slack webhook integration" \
--body "Adds Slack webhook support for real-time notifications.
## Changes
- Added Slack webhook Lambda function
- Updated API Gateway with /webhooks/slack route
- Added Slack API key to Secrets Manager
- Updated documentation
## Testing
- [x] Unit tests pass
- [x] Manual testing with sample webhook
- [x] Documentation updated
Closes #123"
# 3. Or create PR via web UI
# Navigate to: https://github.com/craftcodery/compass/compare
PR Template
When creating a PR, include:
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Changes
- List of specific changes
## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests pass
- [ ] Manual testing completed
- [ ] Documentation updated
## Screenshots (if applicable)
Add screenshots for UI changes
## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex code
- [ ] Documentation updated
- [ ] No new warnings generated
- [ ] Tests pass locally
## Related Issues
Closes #123
Code Review Process
- Automated Checks: GitHub Actions runs tests and validation
- Peer Review: At least one team member reviews code
- Address Feedback: Make requested changes
- Approval: Reviewer approves PR
- Merge: PR merged into main
Review Checklist (for reviewers):
- Code follows style guidelines
- Logic is correct and efficient
- Tests are adequate
- Documentation is clear
- No security vulnerabilities
- Breaking changes clearly documented
After PR is Merged
# 1. Update your local main
git checkout main
git pull upstream main
# 2. Delete feature branch locally
git branch -d feature/your-feature-name
# 3. Delete feature branch on fork
git push origin --delete feature/your-feature-name
# 4. Update CHANGELOG.md
# Add entry under [Unreleased] section
Release Process
Version Numbering
We use Semantic Versioning (MAJOR.MINOR.PATCH):
- MAJOR: Breaking changes
- MINOR: New features (backward compatible)
- PATCH: Bug fixes (backward compatible)
Creating a Release
# 1. Update CHANGELOG.md
# Move [Unreleased] entries to new version section
# 2. Commit changelog
git add CHANGELOG.md
git commit -m "chore: prepare release v1.1.0"
git push origin main
# 3. Create and push tag
git tag -a v1.1.0 -m "Release version 1.1.0"
git push origin v1.1.0
# 4. Create GitHub release
gh release create v1.1.0 \
--title "v1.1.0" \
--notes "$(awk '/## \[1.1.0\]/,/## \[1.0.0\]/' CHANGELOG.md | head -n -1)"
# 5. Deploy to production via GitHub Actions
# Automatic on tag push
Documentation
When to Update Documentation
Update documentation when:
- Adding new features
- Changing APIs or interfaces
- Fixing bugs that affect documented behavior
- Improving setup/deployment process
- Adding new integrations
Documentation Structure
docs/
├── setup/ # Getting started guides
├── architecture/ # System architecture & design
├── operations/ # Deployment & maintenance
├── development/ # Contributing & development
├── infrastructure/ # Terraform & AWS details
├── integrations/ # Third-party integrations
└── reference/ # API & configuration reference
Writing Documentation
- Use clear, concise language
- Provide code examples
- Include screenshots for UI changes
- Test all commands and examples
- Keep documentation up to date with code
Getting Help
Resources
- Documentation: https://craftcodery.github.io/compass
- GitHub Issues: https://github.com/craftcodery/compass/issues
- GitHub Discussions: https://github.com/craftcodery/compass/discussions
Asking Questions
When asking for help:
- Check existing documentation first
- Search existing issues
- Provide context and details
- Include error messages and logs
- Describe what you’ve tried
License
By contributing to this project, you agree that your contributions will be licensed under the same license as the project.
Last updated: 2025-12-30