This document provides guidelines for AI coding agents (such as GitHub Copilot, Cursor, Cline, etc.) working on the MAAS project. These rules help ensure consistency, quality, and security across the codebase.
- General Principles
- Code Quality and Verbosity
- Security Requirements
- Documentation Standards
- Collaboration Practices
- Conventional Commits
- Python Guidelines
- Go Guidelines
- Subdirectory-Specific Rules
- Write code that is modular and testable
- Prefer explicit over implicit code
- Follow the project's established patterns and idioms
- Suggest refactoring when code duplication is detected
- Avoid generating large boilerplate unless explicitly requested
- Always check existing code patterns in the same module before introducing new patterns
Write clean, readable code that speaks for itself:
- Better naming over comments: Use clear, descriptive names for variables, functions, and tests instead of explaining unclear code with comments. Avoid abbreviations unless widely understood.
- Avoid trivial comments: Don't comment on obvious logic or implementation details
- Concise documentation: Keep it simple and straightforward
- Clean test code: No verbose docstrings in tests; fixtures should be self-documenting without obvious comments
- Reasonable merge proposals: Keep changes focused and reasonably sized
- Copyright headers: Add copyright header to all new files (update year as needed):
# Copyright 2026 Canonical Ltd. This software is licensed under the # GNU Affero General Public License version 3 (see the file LICENSE).
Only add comments when:
- Explaining why something is done (not what is being done)
- Documenting non-obvious business logic or domain knowledge
- Clarifying complex algorithms
- Noting important gotchas or edge cases
- Providing context that cannot be expressed in code
Across all parts of the codebase:
- Never hardcode credentials, secrets, or tokens
- Validate and sanitize all user inputs
- Use parameterized queries for database access
- Avoid deprecated or insecure libraries
- Follow security best practices for the specific technology stack
- Be especially careful with authentication and authorization code
- Always use secure defaults for cryptographic operations
- Keep inline comments focused on why, not what
- Use concise docstrings for public functions, classes, and modules (purpose and usage, not implementation)
- Avoid redundancy and obvious statements: Don't repeat what the code already shows or state the obvious
- Update README files when functionality changes
- Document API changes immediately
- Keep architecture documentation synchronized with code changes
- Include type hints where applicable
- Follow the project's code review and pull request process
- Tag relevant team members for specialized reviews
- Reference related issues in commits and pull requests
- Link to relevant documentation when making architectural changes
- Ensure code is compatible with the project's current dependency versions
All commits and pull/merge requests must follow the Conventional Commits specification. This ensures consistent, readable commit history and enables automated changelog generation.
<type>[scope][!]: <description>
[body]
[footer(s)]
- type: Kind of change (feat, fix, refactor, perf, test, build, chore, docs)
- scope: Optional - affected component or system (e.g., bootresources, network, security, deps)
- !: Add before colon if commit introduces breaking changes
- description: Brief summary, aim for 72 characters or less
- body: Optional - detailed explanation of the change
- footer: Optional - metadata like
Resolves LP:2066936orBREAKING CHANGE: description
| Type | Purpose |
|---|---|
| feat | A new feature |
| fix | A bug fix (should reference the bug) |
| refactor | Code change that doesn't fix a bug or add a feature |
| perf | Performance improvement |
| test | Adding or correcting tests |
| build | Build, packaging, or dependency changes |
| chore | Changes that don't fit other types (e.g., version bumps) |
| docs | Documentation-only changes |
Use one of these scopes where applicable:
- bootresources: Images download and synchronization
- dhcp: DHCP service
- dns: DNS service
- network: Networking-related changes
- power: Power drivers and machine power management
- security: Security improvements or fixes
- storage: Storage management
- tftp: TFTP service
- deps: Dependency changes
- ci: CI/CD changes
- Use scope when applicable to help categorize and group commits
- For breaking changes, include
!before the colon AND add aBREAKING CHANGE:footer - Always reference related bugs:
Resolves LP:2066936(Launchpad) orResolves GH:123(GitHub) - Keep commit titles concise; put detailed reasoning in the body
- Explain why a change was made, not just what changed
Good commit with breaking change:
feat(bootresources)!: replace tcpdump with maas-netmon
New binary `maas-netmon` is introduced for ARP network discovery.
BREAKING CHANGE: Binary doesn't read PCAP format, thus it is not
possible to pass in stdin or file as an argument anymore.
Good bug fix:
fix(network): correct VLAN configuration parsing
The parser was incorrectly handling tagged VLANs with non-standard
MTU values, causing network interface initialization to fail.
Resolves LP:2066936
Good feature:
feat(bootresources): check if controller has enough disk space
- Don't export images from DB if they don't fit in the disk
- Don't retry downloads on out-of-disk errors
- Notify user about out-of-disk errors
MAAS Python code must adhere to the following standards:
- Line length: Maximum 79 characters (as configured in
pyproject.toml) - Indentation: 4 spaces (no tabs)
- Quotes: Use double quotes for strings
- Formatting: Use Ruff formatter (configured in
pyproject.toml) - Linting: Follow Ruff linting rules (pycodestyle, pyflakes, isort, flake8-bugbear)
- Target Python 3.9+ (check
pyproject.tomlfor exact supported versions) - Avoid using features from Python versions not yet supported
- Use type hints from
typingmodule for compatibility
Follow the isort configuration in pyproject.toml:
- Standard library imports
- Third-party library imports
- MAAS first-party imports (in this order):
apiclientmaasapiservermaasclimaascommonmaasservermaasservicelayermaastestingmetadataserverprovisioningserver
- Use type hints for function signatures
- For new code in
maascommon,maasservicelayer,maasapiserver, andmaastemporalworker, ensure Pyright compliance - Use Pydantic models for data validation where appropriate
- Use
async/awaitpatterns in asynchronous contexts - Be aware of the difference between sync and async database access patterns
- In v3 API code, prefer async patterns
- In legacy Django code, use
deferToDatabasefor database operations in async contexts
- New code: Use SQLAlchemy Core (not ORM) in the service layer
- Legacy code: Continue using Django ORM where already established
- Always use parameterized queries
- Never construct SQL with string concatenation
- Use transactions appropriately
- Write tests using
pytestfor new code - Follow existing test patterns in the subdirectory
- Use appropriate fixtures (
db_connection,services_mock, etc.) - Mock external dependencies appropriately
- Avoid trivial assertions: Don't test obvious behavior or framework functionality
- Keep tests minimal: Write only necessary tests that verify meaningful behavior
- Use builders (Pydantic models) for creating/updating entities in the service layer
- Implement
ClauseFactoryfor reusable query filters - Use
QuerySpecfor filtering in repository methods - Follow the three-tier architecture in v3 API code (repository → service → API)
MAAS Go code (primarily in maasagent and host-info) follows the standards documented in go-style-guide.md.
Key points:
- Follow standard Go formatting (
gofmt/go fmt) - Check
go.modfor Go version (currently Go 1.24.4 formaasagent, Go 1.18 forhost-info) - Use table-driven tests where appropriate
- Follow the microcluster patterns in
maasagent
Purpose: Legacy Django-based region controller server
- Technology: Python, Django, Twisted
- Database: Django ORM (legacy), transitioning to SQLAlchemy where possible
- Key Patterns:
- Use
deferToDatabasefor database calls in async contexts - Follow Django model conventions for existing models
- Maintain backward compatibility with existing APIs
- Add new functionality to service layer when possible
- Use
- Testing: Use Django test fixtures and
testtools. Run tests withbin/test.region - Notes: This is legacy code; prefer adding new features to the v3 API when feasible
Purpose: FastAPI-based v3 REST API (Presentation Layer)
- Technology: Python, FastAPI, Pydantic
- Architecture: Part of the three-tier architecture (API layer)
- Key Patterns:
- Extend
Handlerclass for new endpoints - Use
@handlerdecorator for endpoint methods - Define Pydantic models for requests/responses
- Use
check_permissionsfor authorization - Mock services in tests, not repositories
- Extend
- Testing: Use
APICommonTests,mocked_api_client*fixtures - Authentication: Support Bearer tokens, Django sessionid, and Macaroons
- Documentation: Ensure OpenAPI spec stays accurate
Purpose: Business logic layer for v3 API (Application Layer)
- Technology: Python, SQLAlchemy, Pydantic
- Architecture: Part of the three-tier architecture (Service + Repository layers)
- Key Patterns:
- Repositories use SQLAlchemy Core (not ORM)
- Services contain business logic
- Use builders for create/update operations
- Implement
ClauseFactoryfor reusable filters - Use
QuerySpecfor query filtering - Extend
BaseRepositoryorReadOnlyRepository - Extend
BaseServiceorReadOnlyService
- Testing:
- Test repositories with real database (
db_connectionfixture) - Test services with mocked repositories
- Use
RepositoryCommonTestsandServiceCommonTestsbase classes
- Test repositories with real database (
- Database: Keep table definitions in
db/tables.pysynchronized - Migrations: Use Alembic for schema migrations
- Notes: Read
src/maasservicelayer/README.mdfor detailed architecture
Purpose: Temporal workflow workers
- Technology: Python, Temporal
- Key Patterns:
- Follow Temporal workflow and activity patterns
- Ensure type hints for Pyright compliance
- Use appropriate retry and timeout policies
- Testing: Mock Temporal client in tests
Purpose: Rack controller provisioning services
- Technology: Python, Twisted
- Key Patterns:
- Async operations using Twisted deferreds
- Power driver implementations
- TFTP and HTTP boot services
- Notes: Legacy async patterns; be careful with reactor usage
Purpose: Cloud-init metadata service
- Technology: Python, Django
- Key Patterns:
- Serve metadata to deploying machines
- Handle commissioning and deployment scripts
- Testing: Follow Django testing patterns
Purpose: Command-line interface
- Technology: Python
- Key Patterns:
- CLI command implementations
- User-facing error messages should be clear
- Validate inputs early
Purpose: API client library
- Technology: Python
- Key Patterns:
- HTTP client for MAAS API
- Handle authentication and errors gracefully
Purpose: Common utilities shared across components
- Technology: Python
- Key Patterns:
- Keep dependencies minimal
- Well-tested utility functions
- Ensure Pyright compliance
- Notes: Changes here affect multiple components
Purpose: Testing utilities and fixtures
- Technology: Python, pytest
- Key Patterns:
- Reusable test fixtures
- Database setup helpers
- Pytest plugins
- Notes: Add reusable test utilities here
Purpose: Go-based MAAS agent using microcluster
- Technology: Go 1.24.4, microcluster, Temporal
- Key Patterns:
- Microcluster-based architecture
- DHCP and DNS services
- Temporal workflow integration
- Prometheus metrics
- OpenTelemetry tracing
- Testing: Use Go testing with testify
- Dependencies: Check
go.modbefore adding dependencies - Notes: Modern Go service; follow Go best practices
Purpose: Collect host hardware information
- Technology: Go 1.18, LXD libraries
- Key Patterns:
- Hardware detection and reporting
- Minimal dependencies
- Testing: Standard Go tests
- Notes: Standalone utility for hardware information gathering
Purpose: Performance testing
- Technology: Python
- Key Patterns:
- Performance benchmarks
- Load testing scenarios
- Notes: Add performance tests for critical paths
Purpose: Integration and cross-component tests
- Technology: Python, pytest
- Key Patterns:
- Integration tests
- End-to-end scenarios
- Notes: Tests that span multiple components
The following directories should be ignored by AI coding agents:
src/maas-offline-docs: Documentation artifactssrc/maasui: UI components (separate frontend codebase)
Before submitting code, ensure:
# Python linting and formatting
make lint
# Python tests
make test
# Go tests (in respective directories)
cd src/maasagent && make test
cd src/host-info && go test ./...- Python configuration:
pyproject.toml - Go configuration:
src/maasagent/go.mod,src/host-info/go.mod - Service layer architecture:
src/maasservicelayer/README.md - Database migrations:
src/maasservicelayer/db/alembic/
When in doubt:
- Check existing code in the same subdirectory for patterns
- Review the subdirectory's README if available
- Consult
pyproject.tomlorgo.modfor configuration - Ask the human reviewer for clarification on architectural decisions