Canon
Canon remembers the decisions your repo already made — and makes Claude Code and Cursor follow them automatically.
Governed project decision memory for AI coding agents.
Canon is a local-first CLI that sits between coding agents (Claude Code and Cursor first) and a project's institutional knowledge. It stops agents and new teammates from re-adopting rejected approaches, inventing conventions, or re-asking questions that were already settled.
It is not a chatbot, not another coding agent, not generic RAG, and not a website-first knowledge base. It is the living, agent-native layer for project decisions. It complements CLAUDE.md, AGENTS.md, and ADRs — it does not replace them.
start coding agent
↓
Canon automatically loads relevant active decisions
↓
agent receives them
Why it exists
Static files go stale. Agents forget last month's review thread. Asking people to stop mid-sprint and write an ADR does not survive week three.
Canon mines recent merged PRs (or Git history) and proposes candidate decisions. A human only approves or rejects. Confirmed decisions are injected automatically at the start of the next agent session. Old decisions are superseded, never silently deleted.
How it works
canon initwires local storage and agent integrations.canon suggestreads recent merged PRs or commits and proposes conservative candidates.- You approve or reject. That interaction should take seconds, not a writing session.
- On the next Claude Code session, a SessionStart hook injects relevant active decisions.
- Cursor reads an always-apply project rule that points at the generated snapshot.
Installation
Requires Python 3.11 or newer and Git.
pip install canon-memory
Isolated CLI install (recommended):
pipx install canon-memory
# or
uv tool install canon-memory
The product and CLI are Canon. The PyPI name is canon-memory because canon is taken by an unrelated package.
canon --help
canon --version
If canon is not recognized (common on Windows user installs):
python -m canon --version
Add your Python Scripts folder to PATH, or keep using python -m canon.
Quickstart
cd my-project
canon init
canon suggest
canon approve 1
canon inject-preview
Then start Claude Code or a new Cursor Agent chat in the same repository. The agent should see the confirmed decision without you running canon query.
V1 does not auto-inject into ChatGPT or standalone Grok. Those tools can only see Canon if you attach .canon/injection.md.
Claude Code integration
canon init installs an official SessionStart command hook in .claude/settings.json (exec form, no shell):
{
"type": "command",
"command": "canon",
"args": ["inject", "--for-hook"],
"timeout": 15
}
Claude Code injects the hook's additionalContext at session start, resume, clear, compact, and fork. Output stays under the 10,000 character hook cap.
canon init also writes a small managed rule at .claude/rules/canon.md. It does not rewrite your CLAUDE.md.
Inspect: canon doctor
Disable: canon uninstall
Troubleshoot: confirm canon is on PATH inside the Claude Code environment.
Cursor integration
Cursor has no session-start hook. Canon uses the officially supported project rules mechanism:
.cursor/rules/canon.mdcwithalwaysApply: true@.canon/injection.mdreferenced from that rule.canon/injection.mdregenerated oninit,approve,reject, andsuggest
Limitation: Cursor will not re-read a changed snapshot until a new Agent session (or a rule reload). Approve a decision, then start a new chat. This is a Cursor platform limitation, not a missing Canon command.
CLI commands
| Command | Purpose |
|---|---|
canon init |
Create local storage, schema, and agent wiring. Idempotent. |
canon status |
Project, database, GitHub, and integration status. |
canon suggest |
Mine recent PRs/commits for conservative candidates. |
canon approve [id] |
Candidate → active. May supersede an older decision. |
canon reject <id> |
Candidate → rejected. Record is kept. |
canon list |
List decisions. --active, --superseded, --rejected, --all, --tag. |
canon show <id> |
Full body and provenance. |
canon inject-preview |
Exactly what an agent would receive. |
canon doctor |
Environment and integration checks. |
canon config |
Show or set project configuration. |
canon export |
Portable JSON of stored decisions. |
canon import |
Validated import. |
canon uninstall |
Remove managed integrations. History is kept unless --purge-data. |
canon version |
Print the version. |
Most commands accept --json. Debug with --debug or CANON_DEBUG=1.
Exit codes: 0 success, 1 application error, 2 invalid usage.
Decision lifecycle
candidate → active
candidate → rejected
active → superseded
Rejected and superseded records stay in SQLite. Injection uses active decisions only.
Decision #42
Status: SUPERSEDED
Superseded by: #57
Provenance
Every suggested and approved decision records what Canon actually knows:
- source PR or commit
- source repository
- source date
- confirmation date and confirmer
If a field is unavailable, Canon says so. It never invents PR numbers, hashes, authors, dates, or URLs.
Privacy
The default is local and private. No account is required.
- SQLite, decision history, and injected context stay on disk.
- Network is used only for optional GitHub PR metadata.
- Telemetry is off unless you set
CANON_TELEMETRY=1, and even then V1 only appends local events to.canon/telemetry.jsonl.
See PRIVACY.md.
Security
Canon treats commit messages, PR titles, PR bodies, filenames, and API responses as untrusted data. They are never executed and never treated as instructions. Git and gh run with argument lists, not a shell. SQL is parameterized.
See SECURITY.md.
Configuration
Precedence:
CLI arguments
↓
environment variables
↓
project config (.canon/config.toml)
↓
user config (~/.canon/config.toml)
↓
defaults
Defaults:
| Setting | Default | Meaning |
|---|---|---|
injection.max_decisions |
12 | Hard cap on injected decisions |
injection.max_chars |
4000 | Hard cap on injection characters |
injection.max_tokens |
1000 | Estimated token cap (chars / 4) |
mining.lookback_prs |
20 | Merged PRs to inspect |
mining.lookback_commits |
80 | Commits to inspect when GitHub is unavailable |
mining.min_score |
6 | Conservative suggestion threshold |
privacy.telemetry |
false | Local event log only, off by default |
Copy .env.example if you need environment overrides. Never commit .env.
Troubleshooting
| Symptom | What to do |
|---|---|
not a Canon project |
Run canon init inside a Git repository. |
GitHub CLI is installed, but you are not authenticated |
Run gh auth login, then canon suggest. |
canon is not recognized |
Use python -m canon ... or add Python Scripts to PATH. |
| No candidates | Expected on mechanical/UI-only history. Product/policy and stack choices should appear. |
| Claude session has no decisions | Run canon doctor. Confirm canon is on PATH. Start a new session. |
| Cursor ignores a new decision | Start a new Agent chat after canon approve. |
| Offline | list, status, and inject-preview work without a network. suggest falls back to Git history. |
Development
See CONTRIBUTING.md.
git clone https://github.com/Adarshk18/Canon.git
cd Canon
python -m pip install -e ".[dev]"
pytest
ruff check src tests
mypy
python -m build
Install unreleased main without a checkout:
pip install git+https://github.com/Adarshk18/Canon.git
Testing
pytest covers decision lifecycle, supersession, mining filters, injection budget, CLI commands, path traversal, SQL injection, command injection, and prompt-injection-style repository content.
Roadmap / deferred features
Intentionally not in V1, matching the source product plan:
- Slack or Notion connectors
- Daily multi-project drift engine
- Rich team dashboard
- Deep MCP query interface
- Enterprise self-host packaging
- Organization management and SSO
- Billing and cloud sync
The domain model is isolated from SQLite so those can be added later without rewriting the local core.
Historical name
An earlier plan used the working name DecisionVault. The product is Canon.
License
MIT. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file canon_memory-1.0.1.tar.gz.
File metadata
- Download URL: canon_memory-1.0.1.tar.gz
- Upload date:
- Size: 55.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99a2a27863deefcf1e1399ff217dd5082312c806f552d5bc217baeb3f0e12e93
|
|
| MD5 |
8b82440091f59ff9caaaa6289cf05fc1
|
|
| BLAKE2b-256 |
d5d55397e1a1dd7461be56fcf899c0771dd7695a5517cba33b190b6a2f26ea5b
|
Provenance
The following attestation bundles were made for canon_memory-1.0.1.tar.gz:
Publisher:
publish.yml on Adarshk18/Canon
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
canon_memory-1.0.1.tar.gz -
Subject digest:
99a2a27863deefcf1e1399ff217dd5082312c806f552d5bc217baeb3f0e12e93 - Sigstore transparency entry: 2489110874
- Sigstore integration time:
-
Permalink:
Adarshk18/Canon@9c2409e4e31b12082cd1a1bef9bf4358e0514189 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/Adarshk18
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9c2409e4e31b12082cd1a1bef9bf4358e0514189 -
Trigger Event:
release
-
Statement type:
File details
Details for the file canon_memory-1.0.1-py3-none-any.whl.
File metadata
- Download URL: canon_memory-1.0.1-py3-none-any.whl
- Upload date:
- Size: 54.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
48cc1051eb7f78e8dc9f8568ddc99f23bb0d878e7f52f8e16cbe9208ffa6de34
|
|
| MD5 |
d72545cc6062cd40de9bc91c3b96ea2d
|
|
| BLAKE2b-256 |
a21b24b783e493f40ee58b84417eba24ac9425eec46843e002c5aff42c45aaa3
|
Provenance
The following attestation bundles were made for canon_memory-1.0.1-py3-none-any.whl:
Publisher:
publish.yml on Adarshk18/Canon
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
canon_memory-1.0.1-py3-none-any.whl -
Subject digest:
48cc1051eb7f78e8dc9f8568ddc99f23bb0d878e7f52f8e16cbe9208ffa6de34 - Sigstore transparency entry: 2489110890
- Sigstore integration time:
-
Permalink:
Adarshk18/Canon@9c2409e4e31b12082cd1a1bef9bf4358e0514189 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/Adarshk18
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9c2409e4e31b12082cd1a1bef9bf4358e0514189 -
Trigger Event:
release
-
Statement type: