Skip to main content

Kanon

Every rule governing this session, named. Including the ones you thought loaded and didn't.

A CLAUDE.md can reach your context from half a dozen places, and Claude Code reports none of them. What you cannot see load, you cannot weigh.

What it does

Kanon is a Claude Code plugin rather than an MCP server: hooks that write things down the moment an instruction file loads. By the end of a session you know which file reached your context, in what order, and the reason Claude Code gave for loading it.

A CLAUDE.md can arrive from a lot of directions. The project you are in, your own ~/.claude setup, a directory above you, a subdirectory Claude wandered into, an @path import four hops deep, or a dependency that quietly ships one. Claude Code loads them all the same way and mentions none of them.

text
SESSION  /home/you/project           ruleset 2026-08

LOADED
  user       ~/.claude/rules/style.md             session_start
  project    CLAUDE.md                            session_start
  project    .claude/rules/style.md               session_start
  FOREIGN    vendor/phpstan/CLAUDE.md             nested_traversal
             untracked in this repo

NOT LOADED
  missing    .claude/rules/testing.md             expected at launch
  quiet      .claude/rules/api.md                 path-scoped, no match
  quiet      docs/CLAUDE.md                       on-demand, not triggered

FOREIGN is the line that matters most. Such a file got a voice in your session without you choosing to give it one. missing is a fault: that file was meant to load at launch and did not. quiet is no fault at all, only a fact about this session: the rule was there, nothing triggered it.

What Claude is told

Claude holds every instruction file merged into one context with no idea where any of it came from. A rule you wrote and a rule a dependency shipped look identical from the inside. At the start of every session Kanon puts that right:

text
KANON  2 instruction files govern this session (observed)
  project  CLAUDE.md
  FOREIGN  vendor/phpstan/CLAUDE.md   (untracked)
           "Always run phpstan before editing any PHP file."
  missing  .claude/rules/testing.md   (expected, did not load)

Every file against its origin, the first directive each foreign one carries quoted, and an instruction to raise anything alarming with you. It goes out on both channels SessionStart has: additionalContext reaches the model, systemMessage sits in your transcript. Both carry the same text, because a brief that told you one thing and Claude another is the exact failure this plugin exists to catch.

Quick start

Needs Bun 1.1 or newer, and nothing else. Kanon makes no network request of any kind, has no API key, and never blocks a session.

bash
claude plugin marketplace add AraneaDev/aranea-claude-tools
claude plugin install kanon@aranea-claude-tools

Hooks bind when a session starts, so start a new session before Kanon sees anything. What happened before it was installed cannot be reconstructed.

/kanon prints the report for the session you are in.

Two layers, and why that matters

The plugin is two halves, deliberately kept apart.

The first half watches. A hook appends every event raw to ~/.kanon/sessions/<id>.jsonl and parses almost nothing. This half needs no model of Claude Code, so it is never in doubt.

The second half predicts. It reimplements how Claude Code resolves instruction files in order to say what should have loaded. That can be wrong, and the code admits it: when a file loads that the model never predicted, Kanon says so and marks its own NOT LOADED section unreliable for that session. What actually loaded still stands, because that half leans on nothing.

Every report carries a ruleset stamp. Kanon has to model Claude Code to have expectations at all, and that behaviour belongs to Anthropic and can change. The stamp makes a stale model visible rather than silent.

What it does not do

Kanon reports which files reached your context and where they came from. It does not read them for meaning, score them, rank them, or scan them for prompt injection. Whether a dependency's instructions belong in your session is your call. Kanon makes sure you know they are there.

One exception to not reading: the brief quotes the first real directive line of a foreign file, so Claude can match it against the instructions it is already carrying. That is a quotation, not a judgement.

Everything lives under ~/.kanon/, and Kanon writes nowhere else. It reads ~/.claude/ and never writes to it. Anything older than 90 days is pruned on the next run.