Skip to main content

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

  1. Fork the repository on GitHub
  2. Clone your fork:
    git clone https://github.com/YOUR_USERNAME/CitadelMesh.git
    cd CitadelMesh
  3. 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 feature
  • fix: Bug fix
  • docs: Documentation only
  • test: Adding/updating tests
  • refactor: Code refactoring
  • perf: Performance improvement
  • chore: 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:

ComponentTest TypeCoverage Required
.NET ServicesUnit + Integration>80%
Python AgentsUnit + Integration>80%
OPA PoliciesUnit>90%
MCP AdaptersUnit + 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

  1. Automated checks run first (tests, linting)
  2. Code review by maintainer
  3. Feedback addressed by contributor
  4. Approval and merge by maintainer

Component-Specific Guidelines

Adding OPA Policies

  1. Create policy file in policies/
  2. Add test file *_test.rego
  3. Run opa test policies/
  4. Update policy documentation

Adding MCP Adapters

  1. Create adapter in mcp-servers/
  2. Follow template structure
  3. Add mock mode support
  4. Include OPA integration
  5. Add comprehensive tests
  6. Document in README

Adding Agents

  1. Extend BaseAgent class
  2. Implement build_graph() method
  3. Add event handlers
  4. Include policy checks
  5. Write unit and integration tests
  6. Add example usage

Updating Documentation

  1. Update relevant guides in docs-site/docs/
  2. Follow existing structure
  3. Include code examples
  4. Add to navigation if new page

Getting Help

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! 🏢