Skip to content

aze3ma/canon

Repository files navigation

Canon

Release Go Version Go Report Card License CI codecov

A git-native, deterministic architecture guardrail tool.


📚 Table of Contents


What is Canon?

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

Philosophy

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.

Quick Start

# 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.

Installation

Quick Install (Recommended)

One-line installer (Linux/macOS):

curl -fsSL https://raw.githubusercontent.com/aze3ma/canon/main/install.sh | bash

This script:

  • Detects your OS and architecture
  • Downloads the latest release
  • Installs to /usr/local/bin (or ~/.local/bin if no sudo)
  • Verifies installation

Manual installation options below


Alternative Installation Methods

Binary Releases (Manual)

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.

From Source

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 version

Verify Installation

canon version
# Output: Canon version 0.1.0

Troubleshooting

Command 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 sudo for system-wide installation
  • Or install to user directory (~/.local/bin) without sudo

Usage

Initialize a New Project

canon init

Creates the .canon/ directory structure with:

  • canon.json - Metadata (version, owner, created date)
  • decisions/ - Architectural decisions directory
  • invariants/ - Immutable rules directory
  • constraints/ - Performance/limit constraints directory
  • decisions/example-decision.json - Example file to get started

List All Rules

# Human-readable format
canon list

# JSON output for scripts/CI
canon list --json

Example 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 a Proposed Change

# 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" --json

Example: No violations

$ canon check --change "Add logging to the application"
✓ No canon violations detected

Example: Soft warning (exit code 2)

$ canon check --change "Increase API timeout"
⚠️  Canon warnings detected

Decision: response-time
Severity: SOFT
latency

Example: 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

Explain a Specific Rule

# Get details about a decision, invariant, or constraint
canon explain async-order-processing

# JSON output
canon explain auth-required --json

Example 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]

Version Information

canon version
# Output: Canon version 0.1.0

Export and Import

Export 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.json

Import 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 --overwrite

Example 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)

JSON Output Mode

Canon supports machine-readable JSON output for automation and CI/CD integration. All commands support the --json flag.

Commands with --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

Example Usage

# 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')

Why JSON Mode?

  • 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

CI/CD Integration

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 }}" --json

Exit 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:

File Structure

.canon/
├── canon.json              # Metadata
├── decisions/
│   └── async-order-processing.json
├── invariants/
│   └── payment-immutability.json
└── constraints/
    └── checkout-latency.json

Creating Custom Rules

Decision Example

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"]
}

Invariant Example

Create .canon/invariants/auth-required.json:

{
  "id": "auth-required",
  "description": "All API endpoints must require authentication",
  "scope": ["api", "security"],
  "severity": "hard"
}

Constraint Example

Create .canon/constraints/response-time.json:

{
  "id": "response-time",
  "type": "latency",
  "limit_ms": 500,
  "scope": ["api"],
  "severity": "soft"
}

Severity Levels

  • hard - Blocking violations (exit code 1). Changes must be rejected.
  • soft - Warnings (exit code 2). Informational, can proceed with caution.

Exit Codes

Code Meaning
0 No issues
1 Hard violation (must stop)
2 Warnings only

AI Integration

Canon is designed to work seamlessly with AI coding assistants and autonomous agents. Here's how to integrate:

For AI Agents

When working in a codebase that uses Canon:

  1. Check the .canon/ directory - This contains all architectural rules and constraints
  2. Before proposing changes, run: canon check --change "your proposed change" --json
  3. Parse the JSON output to determine if the change violates any rules
  4. 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)

Example AI Workflow

# 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"

Integrating Canon into AI Instructions

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 approval

For 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

Development

# Build
go build ./cmd/canon

# Test
go test ./...

# Install
go install ./cmd/canon

More Resources


License

MIT - see LICENSE for details

About

A git-native, deterministic architecture guardrail tool.

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

No packages published