Contributing to CitadelMesh
Welcome! This guide covers everything you need to contribute to CitadelMesh.
Code of Conduct
CitadelMesh follows the Contributor Covenant Code of Conduct. By participating, you agree to uphold this code.
Quick Start
# Fork and clone
git clone https://github.com/YOUR_USERNAME/CitadelMesh.git
cd CitadelMesh
# Create branch
git checkout -b feature/my-contribution
# Make changes
# ...
# Commit and push
git add .
git commit -m "feat: add new feature"
git push origin feature/my-contribution
# Create pull request
gh pr create --title "Add new feature" --body "Description..."
Development Workflow
1. Fork and Clone
- Fork the repository on GitHub
- Clone your fork:
git clone https://github.com/YOUR_USERNAME/CitadelMesh.git
cd CitadelMesh - Add upstream remote:
git remote add upstream https://github.com/Knightwatch/CitadelMesh.git
2. Create Feature Branch
# Update main
git checkout main
git pull upstream main
# Create feature branch
git checkout -b feature/my-feature
# Or for bug fixes
git checkout -b fix/bug-description
3. Make Changes
Follow our coding standards (see below) and ensure:
- Code follows style guidelines
- Tests pass
- Documentation updated
- Commits follow conventions
4. Test Your Changes
# .NET tests
dotnet test
# Python tests
pytest src/agents/tests/
# OPA policy tests
opa test policies/
# MCP adapter tests
cd mcp-servers/my-adapter
npm test
5. Commit Changes
Use Conventional Commits:
# Feature
git commit -m "feat: add door control policy"
# Bug fix
git commit -m "fix: correct temperature range validation"
# Documentation
git commit -m "docs: update OPA policy guide"
# Tests
git commit -m "test: add agent state machine tests"
# Refactor
git commit -m "refactor: simplify event bus connection logic"
Commit Message Format:
<type>(<scope>): <subject>
<body>
<footer>
Types:
feat: New featurefix: Bug fixdocs: Documentation onlytest: Adding/updating testsrefactor: Code refactoringperf: Performance improvementchore: Build/tooling changes
6. Push and Create PR
# Push to your fork
git push origin feature/my-feature
# Create pull request
gh pr create \
--title "feat: add door control policy" \
--body "Implements safety policy for door unlock operations.
## Changes
- Add door_unlock policy in policies/security.rego
- Add policy tests
- Update documentation
## Testing
- All policy tests pass
- Integration tested with security agent
Closes #123"
Coding Standards
.NET (C#)
// Use descriptive names
public class PolicyEnforcer
{
private readonly IOpaClient _opaClient;
// XML documentation for public APIs
/// <summary>
/// Evaluates policy for given action
/// </summary>
/// <param name="action">Action to validate</param>
/// <returns>Policy evaluation result</returns>
public async Task<PolicyResult> EvaluateAsync(string action)
{
// Use ConfigureAwait(false) for library code
var result = await _opaClient.EvaluateAsync(action)
.ConfigureAwait(false);
return result;
}
}
// Follow Microsoft C# conventions
// - PascalCase for classes, methods, properties
// - camelCase for local variables, parameters
// - _camelCase for private fields
// - UPPER_CASE for constants
Python
"""Module docstring describing purpose."""
from typing import Optional, Dict, List
import logging
# Follow PEP 8
# - snake_case for functions, variables
# - PascalCase for classes
# - UPPER_CASE for constants
class SecurityAgent(BaseAgent):
"""Security agent for building control.
Coordinates door control and camera analytics
for threat response.
"""
def __init__(self, config: AgentConfig):
"""Initialize security agent.
Args:
config: Agent configuration
"""
super().__init__(config)
self.logger = logging.getLogger(__name__)
async def process_event(
self,
event: CloudEventMessage
) -> Optional[Dict[str, Any]]:
"""Process security event.
Args:
event: CloudEvent message
Returns:
Processing result or None
"""
# Use type hints
# Add docstrings
# Handle errors gracefully
pass
TypeScript
// Use strict mode
// - Enable strict in tsconfig.json
// - Use explicit types
// - Handle null/undefined
interface DetectionResult {
detectionId: string;
confidence: number;
zone: string;
timestamp: string;
}
export class AvigilonClient {
private readonly apiUrl: string;
private readonly apiKey: string;
constructor(apiUrl: string, apiKey: string) {
this.apiUrl = apiUrl;
this.apiKey = apiKey;
}
/**
* Detect persons in zone
* @param zone - Zone to monitor
* @param threshold - Confidence threshold (0.0-1.0)
* @returns Detection results
*/
async detectPersons(
zone: string,
threshold: number = 0.8
): Promise<DetectionResult[]> {
// Implementation
}
}
// Use async/await, not callbacks
// Export explicitly
// Document public APIs
Rego (OPA Policies)
# Policy Name
# Purpose: What this protects
# Scope: What actions/systems
package citadel.domain.subdomain
import rego.v1
# Default deny
default allow := false
# Rule with description
# Allow action when conditions met
allow if {
input.action == "target_action"
valid_parameter
not safety_violation
}
# Helper rule with clear name
valid_parameter if {
input.param >= min_value
input.param <= max_value
}
# Use descriptive variable names
# Add comments for complex logic
# Keep rules focused and composable
Documentation Requirements
Code Documentation
All public APIs must have documentation:
// C#: XML documentation
/// <summary>
/// Evaluates OPA policy for building control action
/// </summary>
/// <param name="policyPath">Policy path (e.g., "citadel.security.door_unlock")</param>
/// <param name="input">Policy input data</param>
/// <returns>Policy evaluation result</returns>
public async Task<PolicyResult> EvaluatePolicy(string policyPath, object input)
# Python: Docstrings
async def check_safety_policy(
self,
action: str,
params: Dict[str, Any]
) -> bool:
"""Check OPA safety policy before executing action.
Args:
action: Action to validate (e.g., "door_unlock")
params: Action parameters for policy evaluation
Returns:
True if action is allowed by policy, False otherwise
Raises:
PolicyEngineError: If OPA is unreachable
"""
User Documentation
Update guides when adding features:
- Architecture docs - For new patterns
- Implementation guides - For new capabilities
- API reference - For new APIs
- README - For significant changes
Examples
Provide working examples:
# examples/my-feature.py
"""Example demonstrating new feature."""
async def main():
# Setup
agent = MyAgent(config)
# Use feature
result = await agent.new_feature()
print(f"Result: {result}")
if __name__ == "__main__":
asyncio.run(main())
Testing Requirements
Required Tests
All contributions must include tests:
| Component | Test Type | Coverage Required |
|---|---|---|
| .NET Services | Unit + Integration | >80% |
| Python Agents | Unit + Integration | >80% |
| OPA Policies | Unit | >90% |
| MCP Adapters | Unit + Integration | >80% |
Test Patterns
# Python tests
import pytest
@pytest.mark.asyncio
async def test_feature():
"""Test new feature works correctly."""
# Arrange
agent = create_test_agent()
# Act
result = await agent.new_feature()
# Assert
assert result.success == True
assert result.data is not None
// C# tests
[Fact]
public async Task NewFeature_WithValidInput_ReturnsSuccess()
{
// Arrange
var service = new MyService();
var input = new ValidInput();
// Act
var result = await service.NewFeature(input);
// Assert
result.Should().BeSuccessful();
result.Data.Should().NotBeNull();
}
# OPA policy tests
package citadel.security
import rego.v1
test_allow_valid_action if {
allow with input as {
"action": "door_unlock",
"duration_seconds": 300
}
}
test_deny_excessive_duration if {
not allow with input as {
"action": "door_unlock",
"duration_seconds": 1000
}
}
Pull Request Process
PR Checklist
Before submitting:
- Code follows style guidelines
- Tests added/updated and passing
- Documentation updated
- Commits follow conventional format
- PR description is complete
- All CI checks pass
- No merge conflicts
PR Template
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Changes Made
- Change 1
- Change 2
## Testing
How was this tested?
## Screenshots (if applicable)
## Checklist
- [ ] Tests pass
- [ ] Documentation updated
- [ ] Follows coding standards
## Related Issues
Closes #123
Review Process
- Automated checks run first (tests, linting)
- Code review by maintainer
- Feedback addressed by contributor
- Approval and merge by maintainer
Component-Specific Guidelines
Adding OPA Policies
- Create policy file in
policies/ - Add test file
*_test.rego - Run
opa test policies/ - Update policy documentation
Adding MCP Adapters
- Create adapter in
mcp-servers/ - Follow template structure
- Add mock mode support
- Include OPA integration
- Add comprehensive tests
- Document in README
Adding Agents
- Extend
BaseAgentclass - Implement
build_graph()method - Add event handlers
- Include policy checks
- Write unit and integration tests
- Add example usage
Updating Documentation
- Update relevant guides in
docs-site/docs/ - Follow existing structure
- Include code examples
- Add to navigation if new page
Getting Help
- Questions: Open Discussion
- Bugs: Open Issue
- Features: Open Feature Request
- Security: Email security@citadelmesh.io
Recognition
Contributors are recognized in:
- README.md Contributors section
- Release notes
- Documentation
Thank you for contributing to CitadelMesh!
Together we're building the future of intelligent buildings! 🏢