A git-native, deterministic architecture guardrail tool.
- What is Canon?
- Philosophy
- Quick Start
- Installation
- Usage
- CI/CD Integration
- Creating Custom Rules
- AI Integration
- Development
- License
Canon defines the canonical truths of your codebase and enforces them consistently.
These truths include:
- Decisions — Deliberate architectural choices
- Invariants — Rules that must never be broken
- Constraints — Guiding limits for tradeoffs
Canon is intentionally "dumb." It does not reason, guess, or infer. It stores truth and enforces it deterministically.
This makes Canon the authoritative, predictable source of truth for your architecture.
# Initialize Canon in your repo
canon init
# List all canonical rules
canon list
# Check if a change is allowed
canon check --change "Make order processing synchronous"
# Explain a specific rule
canon explain async-order-processing📖 New to Canon? Check out the comprehensive examples guide with real-world scenarios.
One-line installer (Linux/macOS):
curl -fsSL https://raw.githubusercontent.com/aze3ma/canon/main/install.sh | bashThis script:
- Detects your OS and architecture
- Downloads the latest release
- Installs to
/usr/local/bin(or~/.local/binif no sudo) - Verifies installation
Manual installation options below ↓
Download pre-built binaries from the releases page:
Linux:
curl -L https://github.com/aze3ma/canon/releases/latest/download/canon-linux-amd64 -o canon
chmod +x canon
sudo mv canon /usr/local/bin/macOS:
curl -L https://github.com/aze3ma/canon/releases/latest/download/canon-darwin-amd64 -o canon
chmod +x canon
sudo mv canon /usr/local/bin/Windows:
Download canon-windows-amd64.exe from releases and add to your PATH.
Prerequisites: Go 1.23
# Clone repository
git clone https://github.com/aze3ma/canon.git
cd canon
# Option 1: Install directly
go install ./cmd/canon
# Option 2: Build and install
make install
# Option 3: Build for development
make build
./canon versioncanon version
# Output: Canon version 0.1.0Command not found:
- Ensure installation directory is in your
$PATH - For
~/.local/bin, add to your shell profile:export PATH="$HOME/.local/bin:$PATH"
Permission denied:
- Use
sudofor system-wide installation - Or install to user directory (
~/.local/bin) without sudo
canon initCreates the .canon/ directory structure with:
canon.json- Metadata (version, owner, created date)decisions/- Architectural decisions directoryinvariants/- Immutable rules directoryconstraints/- Performance/limit constraints directorydecisions/example-decision.json- Example file to get started
# Human-readable format
canon list
# JSON output for scripts/CI
canon list --jsonExample output:
Canon uses styled terminal output with colors, tables, and boxes for better readability. All commands support --json for machine-readable output.
Decisions (2)
╭──────────────────────┬──────────┬─────────────────────────────────────╮
│ID │SEVERITY │SUMMARY │
├──────────────────────┼──────────┼─────────────────────────────────────┤
│async-order-processing│HARD │Use asynchronous processing for orders│
│cache-strategy │SOFT │Use Redis for caching layer │
╰──────────────────────┴──────────┴─────────────────────────────────────╯
Note: Actual output includes colors and styling. Screenshots available in the releases.
# Check if a change violates any rules
canon check --change "Make order processing synchronous"
# JSON output for CI/CD integration
canon check --change "Add unauthenticated endpoint" --jsonExample: No violations
$ canon check --change "Add logging to the application"
✓ No canon violations detectedExample: Soft warning (exit code 2)
$ canon check --change "Increase API timeout"
⚠️ Canon warnings detected
Decision: response-time
Severity: SOFT
latencyExample: Hard violation (exit code 1)
$ canon check --change "Make order processing synchronous"
❌ Canon violation detected
Decision: async-order-processing
Severity: HARD
Use asynchronous processing for orders
Rationale: Scalability and fault isolation under peak load# Get details about a decision, invariant, or constraint
canon explain async-order-processing
# JSON output
canon explain auth-required --jsonExample output:
Decision: async-order-processing
Status: accepted
Severity: HARD
Summary: Use asynchronous processing for orders
Rationale: Scalability and fault isolation under peak load
Scope: [orders, processing]
Tags: [async, performance, scalability]
canon version
# Output: Canon version 0.1.0Export all canon rules to a single JSON file for backup or sharing:
# Export to default file (canon-export.json)
canon export
# Export to custom file
canon export -o backup.jsonImport canon rules from a JSON file:
# Import from a file (requires .canon/ to exist)
canon import -i canon-export.json
# Import and overwrite existing files
canon import -i backup.json --overwriteExample export output:
✓ Exported canon to canon-export.json
Exported:
2 decisions
1 invariants
1 constraints
Example import output:
✓ Import complete
Imported: 4 files
Skipped: 1 files (already exist, use --overwrite to replace)
Canon supports machine-readable JSON output for automation and CI/CD integration. All commands support the --json flag.
| Command | Human Output | JSON Output | Use Case |
|---|---|---|---|
check |
Styled findings table | {"findings": [...], "exit_code": N} |
CI/CD pipeline integration |
list |
Three styled tables | {"decisions": [...], "invariants": [...], "constraints": [...]} |
Inventory scripts, documentation generation |
explain |
Styled info box | {...decision/invariant/constraint object...} |
Automated documentation, rule analysis |
init |
Success message | {"canon_dir": ".canon", "created_dirs": [...], "created_files": [...]} |
Infrastructure automation |
version |
Styled banner | {"version": "0.1.0", "commit": "...", "date": "..."} |
Version tracking scripts |
export |
Success message | {"exported_file": "...", "decisions_count": N, ...} |
Backup automation |
import |
Success message | {"imported_file": "...", "total_imported": N, ...} |
Migration scripts |
# CI/CD: Check PR title and parse results
canon check --change "$PR_TITLE" --json | jq '.exit_code'
# Automation: Count total rules
canon list --json | jq '[.decisions, .invariants, .constraints] | add | length'
# Documentation: Extract all hard severity rules
canon list --json | jq '.decisions[] | select(.severity == "hard")'
# Infrastructure: Verify initialization
canon init --json | jq '.created_dirs | length'
# Scripts: Get version info
VERSION=$(canon version --json | jq -r '.version')- Deterministic: Same input always produces same output
- Parseable: Easy to integrate with jq, Python, Node.js, etc.
- CI-Friendly: Exit codes + structured data enable robust pipelines
- Automation-Ready: All commands are scriptable
Canon is designed for automated checks in your pipeline:
# GitHub Actions example
- name: Check architectural compliance
run: |
canon check --change "${{ github.event.pull_request.title }}" --jsonExit codes:
0- No violations (safe to proceed)1- Hard violations (block merge)2- Soft warnings (proceed with caution)
📖 Full CI/CD guide with examples for GitHub Actions, GitLab CI, and more:
- Coming soon:
docs/CI_INTEGRATION.md - Pre-commit hooks and automation
.canon/
├── canon.json # Metadata
├── decisions/
│ └── async-order-processing.json
├── invariants/
│ └── payment-immutability.json
└── constraints/
└── checkout-latency.json
Create .canon/decisions/async-order-processing.json:
{
"id": "async-order-processing",
"status": "accepted",
"summary": "Use asynchronous processing for orders",
"rationale": "Scalability and fault isolation under peak load",
"severity": "hard",
"scope": ["orders", "processing"],
"tags": ["async", "performance", "scalability"]
}Create .canon/invariants/auth-required.json:
{
"id": "auth-required",
"description": "All API endpoints must require authentication",
"scope": ["api", "security"],
"severity": "hard"
}Create .canon/constraints/response-time.json:
{
"id": "response-time",
"type": "latency",
"limit_ms": 500,
"scope": ["api"],
"severity": "soft"
}hard- Blocking violations (exit code 1). Changes must be rejected.soft- Warnings (exit code 2). Informational, can proceed with caution.
| Code | Meaning |
|---|---|
| 0 | No issues |
| 1 | Hard violation (must stop) |
| 2 | Warnings only |
Canon is designed to work seamlessly with AI coding assistants and autonomous agents. Here's how to integrate:
When working in a codebase that uses Canon:
- Check the
.canon/directory - This contains all architectural rules and constraints - Before proposing changes, run:
canon check --change "your proposed change" --json - Parse the JSON output to determine if the change violates any rules
- Respect exit codes:
- Exit code 1 = Hard violation (must not proceed)
- Exit code 2 = Soft warning (proceed with caution)
- Exit code 0 = No violations (safe to proceed)
# AI agent checks before making a change
RESPONSE=$(canon check --change "Make order processing synchronous" --json)
EXIT_CODE=$(echo $RESPONSE | jq -r '.exit_code')
if [ $EXIT_CODE -eq 1 ]; then
echo "❌ Cannot proceed: Hard violation detected"
exit 1
elif [ $EXIT_CODE -eq 2 ]; then
echo "⚠️ Warning: Soft constraint violation"
# Proceed with caution or ask user
fi
# Safe to proceed with the change
echo "✓ No violations, proceeding with change"Add this to your AI coding assistant's configuration:
Before making architectural changes, check Canon:
- Run `canon check --change "description"` before proposing changes
- The `.canon/` directory contains all architectural decisions
- Exit code 1 = MUST NOT proceed
- Exit code 2 = Proceed with user approvalFor Cursor (.cursorrules):
Before proposing architectural changes:
1. Check if .canon/ directory exists
2. Run: canon check --change "brief description" --json
3. Parse exit_code from JSON response
4. Exit code 1 = DO NOT make the change (hard violation)
5. Exit code 2 = Ask user before proceeding (soft warning)
6. Exit code 0 = Safe to proceed
For Windsurf (.windsurfrules or project settings):
Architectural Guardrails:
- Before code changes, check: canon check --change "description" --json
- Respect exit codes: 1=block, 2=warn, 0=proceed
- The .canon/ directory contains all architectural rules
- Never bypass exit code 1 (hard violations)
For Aider (.aider.conf.yml):
# In your system message or instructions
before_edit: |
Check Canon rules before making changes:
canon check --change "description" --json
Respect exit codes (1=stop, 2=warn, 0=ok)For GitHub Copilot / Generic AI:
Add to your repository root as AI_INSTRUCTIONS.md:
# AI Instructions
Before proposing any architectural changes:
1. Check if .canon/ directory exists
2. Run: `canon check --change "brief description of your change" --json`
3. Parse the JSON response and respect the exit code
4. Exit code 1 = MUST NOT make the change
5. Exit code 2 = Inform user before proceeding
6. Exit code 0 = Proceed with the change# Build
go build ./cmd/canon
# Test
go test ./...
# Install
go install ./cmd/canon- 📖 Examples Guide - Comprehensive usage examples
- 📝 Changelog - Release notes and version history
- 🐛 Issues - Bug reports and feature requests
- 🤝 Contributing - Contribution guidelines
MIT - see LICENSE for details