System Design
Canon is a Python application built on FastAPI, with modular components for spec parsing, agent analysis, and ticket synchronization.
Platform Components
┌──────────────┐ ┌──────────────┐ ┌─────────────┐
│ Doc Engine │ │ Agent Runner │ │ Knowledge │
│ │ │ │ │ Base │
│ Parse all md │ │ Claude calls │ │ Vector DB │
│ Track specs │ │ PR analysis │ │ BM25 index │
│ Diff & delta │ │ Realization │ │ Hybrid │
│ Verify intent │ │ Doc gen │ │ search │
└───────────────┘ └──────────────┘ └─────────────┘
│ │ │
┌────┴───┐ ┌─────┴────┐ ┌─────┴────┐
│ Tickets│ │ Comms │ │Dev Tools │
│ │ │ │ │ │
│ Jira │ │ Slack │ │ MCP │
│ Linear │ │ Teams │ │ VS Code │
│ GitHub │ │ Email │ │ Cursor │
└────────┘ └──────────┘ └──────────┘FastAPI App
File: src/canon/main.py
The main application exposes:
POST /webhook— GitHub App webhook endpointGET /healthz— Health checkPOST /auth/device/code+/auth/device/token— Device Authorization Grant for CLI loginPOST /{org}/api/tickets/*— Server-proxied ticket CRUD (used by CLI sync)- Web routes for the SPA and fallback templates
All webhook events are verified using HMAC SHA-256 signature checking before being dispatched to handlers.
Spec Parser
Files: src/canon/parser/
The parser processes markdown spec files into structured Pydantic models:
parse.py— Main parser (frontmatter extraction + section parsing + status comment parsing)models.py— Pydantic models:SpecDocument,SpecSection,AcceptanceCriterionwriter.py— Writes back to spec files (insert ticket links, update status comments)
Parse Flow
Agent Runtime
Files: src/canon/agent/
The Claude agent runtime handles PR analysis:
client.py— Anthropic SDK wrapper with model config and error typesanalyzer.py— Analysis orchestration, response parsing, comment formattingprompts.py— System prompt construction, user message builder, token estimation
Model Configuration
Default values as of the current release — see agent/client.py for the latest:
| Parameter | Value |
|---|---|
| Model | Claude Sonnet 4.5 |
| Max input tokens | 128,000 |
| Max output tokens | 16,000 |
| Temperature | 0 (deterministic) |
Prompt Architecture
The system prompt is assembled from three pieces:
- Base system prompt — Agent role, rules, severity levels
- Realization instructions — AC evaluation criteria (when enabled)
- JSON schema — Structured output enforcement
The user message includes PR metadata, spec summaries, context docs, changed file list, and diffs (budget-limited).
GitHub Client
Files: src/canon/github/
verify.py— HMAC SHA-256 webhook signature verificationclient.py— GitHub API client (JWT auth via GitHub App, httpx)spec_utils.py— Spec file detection and loading from GitHubhandlers/— Event handlers for push, PR, issue_comment, etc.
Ticket Sync
Files: src/canon/sync/
Bidirectional synchronization between spec sections and external ticket systems:
engine.py— Forward/reverse sync logicstatus_map.py— Bidirectional spec-to-ticket status mappingmodels.py— Pydantic models for sync operationsadapters/— Per-system adapters (Jira, Linear, GitHub Issues, API Proxy)
Server-Proxied Sync
Files: src/canon/sync/adapters/api_proxy.py, src/canon/web/ticket_routes.py
When CLI users are logged in (canon login), the sync engine uses the CanonApiAdapter instead of calling GitHub directly. This adapter routes ticket CRUD through the Canon server's /api/tickets/* endpoints, which use the GitHub App installation token. The server endpoints are in web/ticket_routes.py.
Adapter Interface
class TicketAdapter:
async def create_ticket(self, input: CreateTicketInput) -> CreateTicketResult
async def update_ticket(self, id: str, changes: dict) -> None
async def sync_status(self, id: str) -> str
async def link_pr(self, ticket_id: str, pr_url: str) -> None
async def close_ticket(self, id: str, evidence: str) -> NoneConfig Parser
Files: src/canon/config/
parse.py— YAML parsing into Pydantic models with validation
Validates CANON.yaml files and provides typed access to all configuration values. Unknown keys produce warnings rather than errors for forward compatibility.
Cron Jobs
Files: src/canon/cron/
sync_status.py— Standalone reverse sync script run as a Kubernetes CronJob
Periodically polls ticket systems for status changes and updates spec files accordingly.