aiscope

DevTools for your AI coding tools' memory. See what Cursor, Claude Code, and GitHub Copilot actually remember about your project — and where they disagree.

aiscope summary card

What it does

You have .cursorrules. You have .github/copilot-instructions.md. You have CLAUDE.md. You have .github/instructions/python.instructions.md. You have .github/agents/reviewer.agent.md. Maybe a .claude/skills/ folder. Maybe an apps/web/AGENTS.md.

Every one of them is a markdown file silently shoved into the model's context window. None of them know about each other. So you ship code where:

  • One file says "use snake_case", another says "use camelCase".
  • The agent allowlist says tools: [read, search] but your instructions say "use the bash tool to run pytest".
  • Two files repeat the same sentence in slightly different words — burning tokens to tell the model the same thing twice.
  • A python.instructions.md (applyTo: **/*.py) and a typescript.instructions.md (applyTo: **/*.ts) look like a contradiction but never apply to the same file. False alarm.

aiscope is a single, deterministic Rust binary that finds these — and knows the difference between a real conflict and a false alarm.

Three minutes to value

cargo install --git https://github.com/Jayanth-MKV/aiscope
cd your-repo
aiscope .                # interactive TUI
aiscope --diag .         # compiler-grade diagnostics
aiscope check .          # exits non-zero on HIGH conflicts (CI gate)

Where to next

Status

Install

aiscope is a single Rust binary with zero runtime dependencies.

cargo install --git https://github.com/Jayanth-MKV/aiscope

Cargo drops the aiscope binary into ~/.cargo/bin/, which is on your PATH if you installed Rust via rustup.

Verify:

aiscope --version

Pre-built binaries

Each GitHub Release ships pre-built binaries for:

OSArchitecture
Linuxx86_64
Linuxaarch64
macOSx86_64
macOSaarch64 (Apple Silicon)
Windowsx86_64

Download the archive for your platform, extract, and put aiscope somewhere on your PATH.

Each archive ships with a .sha256 file — verify before running:

sha256sum -c aiscope-v0.1.0-x86_64-unknown-linux-gnu.tar.gz.sha256

crates.io

Once published, you'll be able to:

cargo install aiscope

Build requirements

Only needed if you're building from source:

  • Rust 1.85+ (edition 2024)
  • A C linker (cc on macOS / Linux, MSVC on Windows)

That's it. No Node, no Python, no native libs.

Uninstall

cargo uninstall aiscope

Quickstart

cd your-repo
aiscope .

That's it. aiscope will scan your repo for every supported AI memory file, extract rules, find conflicts, and drop you into an interactive TUI.

What happens under the hood

When you run aiscope ., it:

  1. Discovers every memory file across Cursor, Claude Code, and GitHub Copilot — see Tools and subsystems.
  2. Parses YAML frontmatter (applyTo, globs, tools:, …).
  3. Extracts typed assertions (e.g. "prefer snake_case for variables").
  4. Reasons about pairs — checks scope overlap, polarity, severity.
  5. Renders the result via your chosen output mode.

It never makes a network request. It never reads outside the repo unless you pass --user (see Privacy guard).

Output modes

FlagUse it for
(default)Interactive ratatui TUI
--textPlain text — pipe-friendly
--diagCompiler-style diagnostics (miette)
--jsonMachine-readable — for scripts and dashboards
--card out.png1280×720 PNG summary — drop into a tweet or PR

Subcommands

CommandWhat it does
aiscopeScan + render (default scan subcommand)
aiscope checkScan + exit non-zero if HIGH conflicts found (CI gate)
aiscope watchRe-scan on file change

Reasoning modes

FlagBehavior
(default)Uniform — every cross-source pair is candidate. Max recall.
--specificSpecific — uses the subsystem matrix to silence false alarms.

See Reasoning modes for the matrix.

Next

Your first scan

Let's walk through a realistic Copilot-only repo and look at what aiscope finds. No setup beyond cargo install.

The repo

my-repo/
└── .github/
    ├── copilot-instructions.md
    ├── instructions/
    │   ├── python.instructions.md      ← applyTo: **/*.py
    │   └── typescript.instructions.md  ← applyTo: **/*.ts
    ├── prompts/
    │   └── unit-test.prompt.md
    └── agents/
        └── reviewer.agent.md           ← tools: [read, search]

Plus an apps/web/AGENTS.md with the web-team's conventions.

Run it

aiscope --diag .

Sample output:

aiscope · 6 sources · 18 statements · 159 tokens · 14 conflicts (4 high)

─── conflict 1 ───
  × agent tool mismatch: .github/instructions/python.instructions.md says
    "use the bash tool" but agent reviewer excludes it
   ╭─[.github/agents/reviewer.agent.md:8:1]
 8 │ You are a code reviewer. Use snake_case in Python feedback…
   · ─────────────────────────────────────
   ╰────
  help: add the tool to the agent's `tools:` allowlist, or change the instruction

─── conflict 2 ───
  × camelCase disagrees with snake_case
   ╭─[.github/copilot-instructions.md:5:1]
 5 │ - Use **camelCase** for variables and functions.
   · ─────────────────────────────────────
   ╰────
  help: the other side: .github/instructions/python.instructions.md:7: …

What just happened

  • aiscope discovered all 5 sources in the Copilot-only repo plus the path-scoped apps/web/AGENTS.md.
  • It noticed the agent's tools: allowlist excludes bash but an instruction says to use it — flagged as AgentToolMismatch (HIGH).
  • The root copilot-instructions.md has no applyTo, so it applies everywhere — and overlaps with python.instructions.md (which scopes to **/*.py). Their camelCase vs snake_case clash is HIGH.
  • python.instructions.md and typescript.instructions.md also disagree on naming, but their globs don't overlap (**/*.py vs **/*.ts) — so that pair is demoted to Low with a (scopes don't overlap) note.

That last point is what makes aiscope worth running: it doesn't just shout about every cross-file disagreement — it filters out false alarms based on actual scope overlap.

Try the TUI

aiscope .

Press c to filter to conflicts only. Press q to quit.

Try the summary card

aiscope --card scan.png .

Drop scan.png into your PR description.

Where to next

How aiscope thinks

aiscope is a 6-layer deterministic pipeline. Each layer is a pure function of the previous one's output — same input always produces the same diagnostics in the same order. No network. No randomness. No background jobs.

scanner → frontmatter → md-parse → canon → extract → reason → render

Layer 1 — scanner

Walks the repo finding every supported memory file. One scanner per tool:

  • scanner::copilot.github/copilot-instructions.md, .github/{instructions,prompts,agents,chatmodes}/, plus AGENTS.md at any depth (path-scoped).
  • scanner::cursor.cursorrules, .cursor/{rules,commands,agents,modes}/.
  • scanner::claudeCLAUDE.md at any depth (path-scoped), .claude/{agents,commands,skills/*/SKILL.md}, plus opt-in ~/.claude/CLAUDE.md via --user.

A privacy guard ensures the scanner never reads outside the repo unless --user is passed, and never reads transcript history under ~/.claude/projects/.

Layer 2 — frontmatter

Parses the YAML subset used by every memory-file ecosystem (applyTo, globs, alwaysApply, tools:, model:, name:, description:).

The output is a typed Scope containing globs, path prefix, model, and tool allowlist — used later by the reasoner.

Layer 3 — md-parse

Converts each markdown body into a stream of typed Statements (bullets, headings, paragraphs), preserving line numbers and byte offsets so we can later render compiler-style diagnostics with source spans.

Layer 4 — canon

Normalizes each statement: NFKC, smart-quote/dash collapse, light stemming. This is what makes paraphrase detection deterministic without using ML.

Layer 5 — extract

Pattern-based assertion extraction onto typed axes:

  • Naming(Variables | Functions | Types | Files)
  • Indentation(Tabs | Spaces2 | Spaces4 | Spaces8)
  • QuoteStyle(Single | Double)
  • PackageManager(Npm | Yarn | Pnpm | Bun)
  • … and more

Layer 6 — reason

Pair-wise checks. Two assertions become a conflict only when:

  1. The subsystem matrix permits it (in --specific mode).
  2. The scopes overlap (otherwise demoted to Low).
  3. The polarity disagrees on the same axis.

Plus duplicate-name detection across agents/skills/chat modes, plus the agent-tool-allowlist mismatch detector.

Render

Five renderers, all consuming the same typed ContextBundle:

  • ratatui TUI
  • miette compiler-style diagnostics
  • plain text
  • JSON
  • 1280×720 PNG card with embedded JetBrains Mono

Why this shape

Each layer is independently testable. The 42-test suite covers every layer in isolation plus end-to-end snapshots. Determinism + clean layering means you can rely on aiscope check in CI as a stable gate — it'll never flake on you.

Tools and subsystems

aiscope discovers files across 3 tools × 5 subsystems = up to 15 distinct source kinds.

SubsystemWhat it is
InstructionsAlways-on rules the model uses on every turn
PromptsOne-shot snippets the user invokes explicitly
AgentsNamed subagents with their own tool allowlist
ChatModesUI modes that switch the available tools / system prompt
SkillsReusable capability bundles (Claude-specific convention)

GitHub Copilot

SubsystemDiscovered from
Instructions.github/copilot-instructions.md, .github/instructions/*.instructions.md
Prompts.github/prompts/*.prompt.md
Agents.github/agents/*.agent.md, plus AGENTS.md at any depth
ChatModes.github/chatmodes/*.chatmode.md

AGENTS.md is automatically path-scopedapps/web/AGENTS.md gets Scope.path_prefix = "apps/web/**".

Cursor

SubsystemDiscovered from
Instructions.cursorrules (legacy), .cursor/rules/*.md
Prompts.cursor/commands/*.md
Agents.cursor/agents/*.md
ChatModes.cursor/modes/*.md

Claude Code

SubsystemDiscovered from
InstructionsCLAUDE.md at any depth (path-scoped)
Prompts.claude/commands/*.md
Agents.claude/agents/*.md
Skills.claude/skills/*/SKILL.md

The opt-in --user flag also reads ~/.claude/CLAUDE.md (your global instructions). aiscope never reads ~/.claude/projects/ (transcript history) — see Privacy guard.

Why subsystems matter

Different subsystems have different roles. A Prompt is a one-shot override — it's meant to contradict the always-on Instructions. An Agent runs in its own context window — what it says shouldn't conflict with what the main Instructions say.

That's why aiscope ships two reasoning modes: Uniform (default, max recall) and Specific (--specific, subsystem-aware). See Reasoning modes.

Scope and applyTo

The single most important feature of aiscope is scope-aware severity. It's the difference between a tool that flags every cross-file disagreement and a tool you actually trust to gate your CI.

What is a scope?

Every memory file has a scope — which files does this rule apply to? aiscope derives it from three sources:

  1. applyTo / globs frontmatter — explicit glob pattern(s).

    ---
    applyTo: "**/*.py"
    ---
    
  2. alwaysApply: true — explicit "applies everywhere".

  3. File locationapps/web/AGENTS.md is implicitly scoped to apps/web/** because that's where it lives.

If none of these are present, the file applies everywhere.

When do scopes overlap?

Two scopes overlap if any path matches both. aiscope computes this with the globset crate.

Left scopeRight scopeOverlap?
**/*.py**/*.ts❌ no
**/*.py(everywhere)✅ yes
apps/web/**apps/api/**❌ no
apps/web/****/*.ts✅ yes
apps/**apps/web/**✅ yes

How it affects severity

If two files contradict each other but their scopes don't overlap, they can never both apply to the same source file — so it's not really a conflict. aiscope demotes such pairs to Low severity with a (scopes don't overlap) note.

This is what makes aiscope check safe to run in CI: it won't fail your build over a python.instructions.md vs typescript.instructions.md disagreement that can never actually confuse the model.

Tool-allowlist scope

For agents specifically, tools: defines which tools the agent is allowed to invoke:

---
name: reviewer
tools:
  - read
  - search
---

If an instruction file says "use the bash tool to run pytest" but no agent has bash in its allowlist, aiscope flags it as AgentToolMismatch.

See also

Reasoning modes

aiscope ships two reasoning modes. They control which subsystem pairs are even considered for clash detection.

Uniform (default)

Every cross-source pair is a candidate. Maximum recall.

aiscope .
aiscope --diag .

Use Uniform when:

  • You want to catch everything that might confuse the model.
  • You have a small, simple repo with one tool and few files.
  • You're doing the first audit of a new repo.

Specific (--specific)

Subsystem-aware filtering via this matrix:

Left subsystemRight subsystemCan clash?
InstructionsInstructions✅ yes
InstructionsPrompts❌ no
InstructionsAgents❌ no
InstructionsChatModes❌ no
InstructionsSkills❌ no
PromptsPrompts✅ yes
AgentsAgents✅ yes
ChatModesChatModes✅ yes
SkillsSkills✅ yes
aiscope --specific .
aiscope check --specific .

Why these rules?

  • Prompts ↔ Instructions: prompts are intentional one-shot overrides. They should contradict the always-on instructions when the user invokes them.
  • Agents ↔ everything: agents run with their own context window. What an agent says doesn't reach the main session.
  • Skills / ChatModes ↔ anything else: these are also opt-in contexts.

Which should I use in CI?

Use --specific in CI:

- run: aiscope check --specific .

It's the right default for most teams — fewer false positives, still catches the conflicts that actually break model behavior.

Use default Uniform locally when you want to see everything.

Note: AgentToolMismatch is unaffected

The --specific flag only filters cross-subsystem clashes. It does not silence AgentToolMismatch diagnostics — those are always reported, because they're always real bugs.

Conflict kinds

Every diagnostic aiscope emits has a ConflictKind. There are four.

Clash

Two assertions on the same axis (e.g. Naming(Variables)) disagree.

× camelCase disagrees with snake_case

When it fires: any two files that assert different values on the same axis, where their scopes overlap.

How to fix: pick one. Update or delete the loser.

PolarityConflict

One file asserts X, another forbids X — explicit polarity disagreement.

× polarity conflict: "use 4 spaces" vs "do not use 4 spaces"

When it fires: detected via negation patterns in the extractor.

How to fix: same as Clash — pick a side.

Duplicate

Two files say the same thing (after canonicalization).

× duplicate rule across .cursorrules and CLAUDE.md
   help: wastes tokens; remove one.

When it fires: after NFKC normalization + light stemming, two statements match.

How to fix: delete one. Or, if you have multiple tools that intentionally repeat (e.g. you maintain Cursor and Claude rules in parallel), suppress this with aiscope --no-duplicates (planned).

Duplicate also fires on duplicate name: across agents, skills, or chat modes — two agents named reviewer is undefined behavior.

AgentToolMismatch

An agent's tools: allowlist either:

  • Excludes a tool that an instruction says to use:

    python.instructions.md says "use the bash tool" but agent reviewer excludes it

  • Or is empty while the agent body mentions tools — undefined behavior.
× agent tool mismatch: .github/instructions/python.instructions.md says
  "use the bash tool" but agent reviewer excludes it
   help: add the tool to the agent's `tools:` allowlist, or change the instruction

When it fires: cross-checked between every Subsystem::Agents source's scope.tools and every Subsystem::Instructions source's body text.

How to fix: either add the tool to the agent's allowlist, or change the instruction to not require it.

AgentToolMismatch is always reported--specific mode does not silence it.

Severity

Every conflict has a severity:

SeverityWhat it means
HighCross-source AND scopes overlap AND combined-confidence ≥ 0.85. aiscope check exits non-zero.
LowSame source, OR scopes don't overlap, OR low confidence. Informational.

See Scope for the overlap rules.

CLI reference

aiscope [OPTIONS] [PATH]
aiscope <SUBCOMMAND> [OPTIONS] [PATH]

PATH defaults to the current directory.

Global options

FlagDescription
--textPlain text output
--diagCompiler-style diagnostics (miette)
--jsonMachine-readable JSON
--card <FILE>Render a 1280×720 PNG summary card
--specificUse the Specific reasoning mode
--userAlso read user-scope memory (e.g. ~/.claude/CLAUDE.md)
--versionPrint version and exit
--helpPrint help

If none of --text / --diag / --json / --card is passed, aiscope launches the interactive TUI.

Subcommands

aiscope scan (default)

Scan and render. Same as aiscope with no subcommand.

aiscope scan --diag .

aiscope check

Scan and exit non-zero if any HIGH-severity conflicts are found. Designed for CI gates.

aiscope check --specific .
echo $?     # 0 = clean, 1 = HIGH conflicts, 2 = error

See Exit codes.

aiscope watch

Re-scan whenever a memory file changes. Great for live editing.

aiscope watch .

Examples

# Interactive TUI on the current dir
aiscope

# CI-friendly: exit non-zero on HIGH conflicts, suppress false alarms
aiscope check --specific .

# Generate a PR-ready summary card
aiscope --card scan.png .

# Pipe JSON to jq
aiscope --json . | jq '.conflicts[] | select(.severity == "high")'

# Read user-scope memory too (opt-in)
aiscope --user .

Output to stdout vs file

All renderers except --card write to stdout and respect piping. The TUI auto-falls-back to plain text when stdout is not a TTY:

aiscope . > scan.txt    # writes plain text, not TUI escape codes

Interactive TUI

Run aiscope with no output flags to launch the ratatui interface.

aiscope .

Layout

Three panes:

  • Sources (left) — every memory file aiscope discovered, color-coded by tool.
  • Unified context (right) — every rule across every file, with conflicts flagged inline. Each rule shows its applyTo glob in dim gray on the right.
  • Score (bottom) — totals: rules, clashes, duplicates, tokens, waste %.

Keys

KeyAction
q / EscQuit
cToggle conflicts-only filter
/ Scroll one row
j / kSame as ↓ / ↑ (vim-style)
PgUp / PgDnPage scroll

Tool icons

IconTool
Copilot
Cursor
Claude Code

Falling back to text

If stdout is not a TTY (you piped or redirected), aiscope automatically prints plain text instead of TUI escape codes. So aiscope . > scan.txt works naturally.

JSON output

aiscope --json . > scan.json

The full bundle as one JSON object — suitable for scripts, dashboards, and custom integrations.

Schema (top-level)

{
  "root": "/path/to/repo",
  "sources": [
    {
      "tool": "copilot",
      "subsystem": "instructions",
      "path": ".github/copilot-instructions.md",
      "label": ".github/copilot-instructions.md",
      "name": null,
      "description": null,
      "scope": {
        "globs": [],
        "always_apply": false,
        "path_prefix": null,
        "model": null,
        "tools": []
      }
    }
  ],
  "statements": [
    {
      "source_index": 0,
      "text": "Use camelCase for variables and functions.",
      "line": 5,
      "byte_start": 87,
      "byte_end": 130
    }
  ],
  "rules": [
    /* same as statements (legacy alias) */
  ],
  "assertions": [
    {
      "statement_index": 0,
      "axis": { "kind": "naming", "scope": "variables" },
      "value": "camel_case",
      "polarity": "positive",
      "confidence": 0.95
    }
  ],
  "conflicts": [
    {
      "kind": "clash",
      "left": 0,
      "right": 3,
      "axis": { "kind": "naming", "scope": "variables" },
      "note": "camelCase disagrees with snake_case",
      "severity": "high",
      "confidence": 0.93
    }
  ],
  "total_tokens": 159,
  "stale_tokens": 12
}

Recipes

List only HIGH conflicts

aiscope --json . | jq '.conflicts[] | select(.severity == "high")'

Count duplicates

aiscope --json . | jq '[.conflicts[] | select(.kind == "duplicate")] | length'

Find sources with no applyTo

aiscope --json . | jq '.sources[] | select(.scope.globs == []) | .label'

Waste percentage

aiscope --json . | jq '(.stale_tokens / .total_tokens * 100 | floor)'

Stability

The schema follows semver:

  • 0.x: fields may be added; existing fields are stable within a minor.
  • 1.0+: schema is fully stable.

Field names use snake_case to match Rust conventions on the producing side.

Compiler-style diagnostics (--diag)

aiscope --diag .

Renders every conflict as a miette diagnostic with source spans — same look as cargo check.

Sample

× camelCase disagrees with snake_case
   ╭─[.github/copilot-instructions.md:5:1]
 4 │
 5 │ - Use **camelCase** for variables and functions.
   · ─────────────────────────────────────
 6 │
   ╰────
  help: the other side: .github/instructions/python.instructions.md:7:
        "Use snake_case for variables."

Why use it

  • It's the format engineers already read — every Rust dev recognizes it.
  • Source spans take you straight to the offending line.
  • Works in PR comments — looks great pasted into GitHub markdown.

Combine with aiscope check

aiscope check --specific --diag .

Get diagnostic-style output and the non-zero exit code in one command — ideal for pre-commit and CI logs.

Summary card (--card)

aiscope --card scan.png .

Renders a 1280×720 PNG summary card. Designed for:

  • PR descriptions and review threads
  • Tweets / social posts about your repo's hygiene
  • Slack / Discord drops in #engineering channels
  • Conference slides

What's on it

  • Title — repo name (auto-detected from path)
  • Top 3 conflicts — kind icon, short note, severity tag
  • Stats grid — sources, rules, tokens, conflicts
  • Waste %stale_tokens / total_tokens, capped at 100%
  • Footeraiscope · v{VERSION} · {REPO}

Font

Bundles JetBrains Mono Regular (270 KB, OFL license). No system-font lookup — same output on every machine.

Pixel-accurate layout

aiscope measures every glyph with cosmic-text before drawing — no guesswork, no overflow, no clipped text. Long titles are binary-search-truncated to fit with an ellipsis.

Reproducibility

Same input → byte-identical PNG. Useful for golden tests in CI.

Limitations

  • Only Latin / Latin-Extended glyphs render — JetBrains Mono Regular doesn't ship CJK or arrow glyphs like . aiscope uses vs instead.
  • Fixed 1280×720 — no --width / --height flags yet.

Privacy guard

aiscope is a read-only, offline tool by design. Three guarantees:

1. Zero network

aiscope makes no network requests. Ever. No telemetry, no update checks, no crash reporting. You can verify with strace, Wireshark, or by reading the source — there are no reqwest, ureq, or hyper dependencies in the [dependencies] block of Cargo.toml.

2. Zero writes (unless you pass --card)

aiscope opens every file as read-only. The only file it ever writes is the PNG you ask for via --card path.png.

3. Scope respect

By default, aiscope only reads files inside your repo.

  • It does not read ~/.claude/CLAUDE.md unless you pass --user.
  • It never reads ~/.claude/projects/ (your transcript history) — even with --user. That directory is on the explicit deny-list.
  • It does not follow symlinks out of the repo.
  • It respects .gitignore — files ignored by git are skipped.

What about secrets?

Memory files are markdown — they're meant to be committed and shared. aiscope prints the content of those files as part of diagnostics. If you put secrets in copilot-instructions.md, they'll appear in aiscope --diag output. Don't do that.

Want even tighter sandboxing?

firejail --net=none --read-only=/ --read-only=/home/$USER aiscope check .

Or run inside a Docker container with --network=none.

See it for yourself

strace -e trace=network aiscope check .
# (no output — no network syscalls)

GitHub Copilot

aiscope discovers Copilot memory across 4 subsystems plus the ecosystem-standard AGENTS.md.

Files discovered

SubsystemGlob
Instructions.github/copilot-instructions.md
Instructions.github/instructions/*.instructions.md
Prompts.github/prompts/*.prompt.md
Agents.github/agents/*.agent.md
Agents**/AGENTS.md (any depth, path-scoped)
ChatModes.github/chatmodes/*.chatmode.md

Frontmatter

---
applyTo: "**/*.py"
description: "Python conventions"
---
FieldUsed for
applyToScope glob(s) — single string or array
descriptionOptional human label
nameAgent name (used for duplicate detection)
toolsAgent tool allowlist (used for AgentToolMismatch)

AGENTS.md path scoping

apps/web/AGENTS.md is automatically scoped to apps/web/**. So a top-level AGENTS.md saying "use camelCase" and an apps/api/AGENTS.md saying "use snake_case" won't conflict — their scopes don't overlap.

Tips

  • Use one root copilot-instructions.md for cross-cutting rules.
  • Use .github/instructions/<lang>.instructions.md with applyTo for language-specific rules.
  • Move team-specific rules into apps/<team>/AGENTS.md to scope them.

Cursor

aiscope discovers Cursor memory across 4 subsystems, including the legacy single-file format.

Files discovered

SubsystemGlob
Instructions.cursorrules (legacy, single file)
Instructions.cursor/rules/*.md
Prompts.cursor/commands/*.md
Agents.cursor/agents/*.md
ChatModes.cursor/modes/*.md

Frontmatter

---
globs:
  - "**/*.ts"
  - "**/*.tsx"
alwaysApply: false
description: "TypeScript style"
---
FieldUsed for
globsScope glob(s) — array
alwaysApplyIf true, scope is "everywhere"
descriptionOptional human label

Migration tip

If you have a legacy .cursorrules plus modular .cursor/rules/*.md, aiscope will surface both — and likely flag duplicates. Migrate fully to .cursor/rules/ and delete .cursorrules to clean up.

Claude Code

aiscope discovers Claude Code memory across 5 subsystems, including nested skills.

Files discovered

SubsystemGlob
Instructions**/CLAUDE.md (any depth, path-scoped)
Instructions~/.claude/CLAUDE.md (only with --user)
Prompts.claude/commands/*.md
Agents.claude/agents/*.md
Skills.claude/skills/*/SKILL.md

What aiscope deliberately ignores

  • ~/.claude/projects/ — your transcript history. Never read, even with --user.
  • Anything outside the repo (unless --user is passed and the path is exactly ~/.claude/CLAUDE.md).

See Privacy guard.

Frontmatter

---
name: reviewer
description: "Reviews code for Python style"
tools:
  - read
  - search
model: sonnet-4
---
FieldUsed for
nameUsed for duplicate-name detection across agents
descriptionOptional human label
toolsAgent tool allowlist (used for AgentToolMismatch)
modelOptional model hint

CLAUDE.md path scoping

Just like AGENTS.md for Copilot — a CLAUDE.md in apps/api/ is scoped to apps/api/** automatically.

--user opt-in

aiscope --user .

Reads your global Claude memory at ~/.claude/CLAUDE.md so cross-project rules show up too. Strict allowlist — no other files outside the repo are read.

AGENTS.md

The AGENTS.md file is a tool-agnostic convention emerging across the ecosystem — Copilot, Cursor, Claude, and Codex all read it. aiscope treats it as a first-class source.

Discovery

aiscope finds AGENTS.md at any depth in the repo and assigns it to the Copilot Agents subsystem by convention.

Path scoping

The file's directory becomes its scope's path_prefix:

File locationScope
AGENTS.mdeverywhere
apps/web/AGENTS.mdapps/web/**
services/api/AGENTS.mdservices/api/**

This means a top-level AGENTS.md and a apps/web/AGENTS.md will not conflict on naming rules unless both apply to overlapping paths — perfect for monorepos.

Why use it

If you want one source of truth that all your AI tools read, put it in AGENTS.md. Most modern AI tools will pick it up automatically, and aiscope will validate its consistency with everything else.

Example

# AGENTS.md

## Code style

- Use 2-space indentation
- Prefer single quotes in TypeScript
- Use snake_case for Python

## Testing

- Every PR must include tests for new public APIs

No frontmatter needed — the file applies to its directory and below.

GitHub Actions

Gate every PR with aiscope check. Add this workflow to your repo:

.github/workflows/aiscope.yml:

name: aiscope

on:
  pull_request:
  push:
    branches: [main]

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo
        uses: Swatinem/rust-cache@v2

      - name: Install aiscope
        run: cargo install --locked aiscope

      - name: Check AI memory consistency
        run: aiscope check --specific --diag .

Output in PR logs

Because --diag produces compiler-style output, the diagnostics render beautifully in the GitHub Actions log viewer. Reviewers can read and act on them without leaving the PR.

Failing fast

aiscope check exits non-zero on any HIGH-severity conflict. The job fails, the PR turns red, and the merge button is blocked (if you require checks to pass).

Generating a PR comment with the card

Combine with stefanzweifel/git-auto-commit-action or a custom comment step:

- name: Render summary card
  run: aiscope --card aiscope.png .

- name: Upload card
  uses: actions/upload-artifact@v4
  with:
    name: aiscope-card
    path: aiscope.png

Speed

aiscope is fast — sub-second on typical repos, single-digit seconds on huge monorepos. Adding it to CI adds negligible latency.

Pre-commit hook

Catch conflicts before they ever reach a PR.

Using pre-commit

.pre-commit-config.yaml:

repos:
  - repo: local
    hooks:
      - id: aiscope
        name: aiscope (AI memory consistency)
        entry: aiscope check --specific .
        language: system
        pass_filenames: false
        files: '\.(md|mdx)$'

Then:

pre-commit install

The hook runs aiscope check whenever you change any markdown file.

Plain .git/hooks/pre-commit

If you don't want pre-commit:

#!/usr/bin/env bash
set -euo pipefail
exec aiscope check --specific .

Save as .git/hooks/pre-commit and chmod +x it.

Speed

aiscope is sub-second on typical repos — the hook is essentially free.

Exit codes

CodeMeaning
0Success — no HIGH-severity conflicts
1One or more HIGH-severity conflicts found (aiscope check only)
2Argument or I/O error

Behavior by command

CommandExits non-zero on HIGH conflicts?
aiscope❌ no — informational only
aiscope scan❌ no — same as above
aiscope check✅ yes — exits 1
aiscope watch❌ no — runs forever

Why scan doesn't fail

scan is for inspection (TUI, JSON, card). Failing it would break dashboards and watch loops. Use check whenever you want a hard gate.

CI snippet

- run: aiscope check --specific .
  # exit 1 fails the job; no extra config needed

Frontmatter fields

Every supported field across every tool, in one table.

FieldToolsTypeUsed for
applyToCopilotstring | arrayScope glob
globsCursorarrayScope glob
alwaysApplyCursorboolForce "everywhere" scope
nameAll (agents, skills, modes)stringDuplicate-name detection
descriptionAllstringHuman label (shown in TUI/card)
toolsCopilot, Claude (agents)arrayAgent tool allowlist
modelCopilot, Claude (agents)stringOptional model hint (informational)

Parsing rules

  • aiscope uses serde_yaml under the hood.
  • Unknown fields are ignored, not errored — forward-compatible with whatever Copilot/Cursor/Claude add next.
  • Missing fields fall back to defaults (no scope = everywhere).
  • Both --- and +++ (TOML) delimiters are recognized.

Glob syntax

aiscope uses globset — same syntax as git:

PatternMatches
*.pyany .py in the current dir
**/*.pyany .py at any depth
apps/web/**everything under apps/web/
!**/test_*.pyexclusions are not yet supported

Examples

---
applyTo: "**/*.py" # Copilot
---
---
globs: # Cursor
  - "**/*.ts"
  - "**/*.tsx"
alwaysApply: false
---
---
name: reviewer # Claude / Copilot agent
description: "Reviews PRs"
tools: [read, search]
model: sonnet-4
---

Architecture

aiscope is a 6-layer deterministic pipeline. This page maps the layers to the actual source modules.

┌─────────┐  ┌─────────────┐  ┌──────────┐  ┌───────┐  ┌─────────┐  ┌────────┐  ┌────────┐
│ scanner │→ │ frontmatter │→ │ md-parse │→ │ canon │→ │ extract │→ │ reason │→ │ render │
└─────────┘  └─────────────┘  └──────────┘  └───────┘  └─────────┘  └────────┘  └────────┘

Module layout

src/
├── main.rs                  # entry, CLI dispatch
├── cli.rs                   # clap arg model
├── lib.rs                   # public API, ContextBundle
├── types.rs                 # Source, Statement, Assertion, Conflict, Scope
├── scanner/
│   ├── mod.rs               # discover() entry point
│   ├── common.rs            # walkdir helpers, gitignore filter
│   ├── copilot.rs           # .github/* + AGENTS.md
│   ├── cursor.rs            # .cursor/* + .cursorrules
│   └── claude.rs            # CLAUDE.md + .claude/* + --user
├── frontmatter/
│   └── mod.rs               # YAML/TOML parser → Scope
├── parse.rs                 # markdown → Statement[]
├── canon.rs                 # NFKC + light stemming
├── extract/
│   ├── mod.rs
│   └── pattern.rs           # regex assertion extractors
├── reason/
│   ├── mod.rs
│   ├── matrix.rs            # Specific-mode subsystem table
│   ├── overlap.rs           # globset-based scope overlap
│   └── tools.rs             # AgentToolMismatch detector
└── render/
    ├── tui.rs               # ratatui interactive
    ├── text.rs              # plain text
    ├── diag.rs              # miette
    ├── json.rs              # serde_json
    └── card.rs              # tiny-skia + cosmic-text PNG

Key types

#![allow(unused)]
fn main() {
pub struct ContextBundle {
    pub root: PathBuf,
    pub sources: Vec<Source>,
    pub statements: Vec<Statement>,
    pub assertions: Vec<Assertion>,
    pub conflicts: Vec<Conflict>,
    pub total_tokens: usize,
    pub stale_tokens: usize,
}
}

Every renderer takes &ContextBundle. Adding a new output format means one new module — nothing else changes.

Determinism

  • walkdir results are sorted before consumption.
  • HashMap is never iterated for output — we use BTreeMap or sort first.
  • No threads, no async runtime, no clock reads in the hot path.

Same input → byte-identical JSON, byte-identical card PNG, identical diagnostic line order. This is what makes aiscope check safe to wire into CI.

Test suite

42 tests across:

  • per-module unit tests (frontmatter, canon, extract, overlap, matrix)
  • end-to-end fixtures (tests/fixtures/) with golden snapshots
  • copilot-only fixture proving single-tool repos work
  • privacy-guard tests asserting ~/.claude/projects/ is never read

Run cargo test to see.

FAQ

Does aiscope make network requests?

No. Zero. See Privacy guard.

Does aiscope write to my files?

No, except the PNG you ask for via --card path.png.

Will it work on a repo with only Copilot files?

Yes. There's even a dedicated test fixture for it. Single-tool repos are fully supported.

Why does aiscope flag two files that can't both apply (different applyTo globs)?

It doesn't — by default, non-overlapping scopes are demoted to Low severity. aiscope check only fails on High. See Scope.

My --specific mode hides a conflict I want to see. How do I get it back?

Drop the flag — default mode (Uniform) shows everything. Or use --diag / --text to see Low-severity items inline.

Does aiscope support [tool I just thought of]?

If the tool stores rules as markdown with optional YAML frontmatter, opening an issue with paths and conventions is the easiest path. Adding a new scanner module is ~50 lines.

Why JetBrains Mono and not [other font]?

Free, open source (OFL), great Latin coverage, looks professional. The font is bundled (270 KB) so the card renders identically on every machine.

My card shows vs instead of . Why?

JetBrains Mono Regular doesn't ship the glyph (U+21C4). Rather than fall back to a system font (which would break reproducibility), aiscope uses vs. See Summary card.

Is the JSON schema stable?

Within a 0.x minor: fields may be added but existing fields are stable. Starting at 1.0: fully stable.

Can I run aiscope on a non-git directory?

Yes. aiscope honors .gitignore if present but doesn't require git.

Where does the 4% context wasted number come from?

stale_tokens / total_tokens, where stale_tokens is the size of any statement involved in a Duplicate or losing side of a clash.

Troubleshooting

"command not found: aiscope"

Cargo's bin directory isn't on your PATH. Add it:

  • Linux / macOS: add export PATH="$HOME/.cargo/bin:$PATH" to your shell rc file.
  • Windows (PowerShell): $env:Path += ";$env:USERPROFILE\.cargo\bin", or update your user Path env var permanently via System Settings.

"no AI memory files found"

Run from your repo root, not a subdirectory. Or pass the path explicitly:

aiscope /path/to/repo

If your repo legitimately has no memory files, that's the expected output.

TUI looks broken / shows escape codes

Your terminal doesn't fully support the cursor protocol. Use --text:

aiscope --text .

aiscope check always passes even with conflicts

check only fails on High-severity conflicts. If everything is Low (typically because scopes don't overlap), exit code is 0. Use --text or --diag to see Low items.

Card overflows / text is clipped

Please open an issue with the input that triggered it. As of v0.1.0 the card uses pixel-accurate text measurement and binary-search truncation — overflow should be impossible.

Build fails: "cosmic-text requires Rust ≥ 1.85"

Upgrade your toolchain:

rustup update stable

"permission denied" reading some file

aiscope only reads what your user can read. Check file permissions:

ls -la .github/

Everything else

Open an issue — include OS, Rust version, aiscope --version, and the output of aiscope --diag . if relevant.

Changelog

The full changelog lives at the repo root: CHANGELOG.md.

A condensed, in-docs copy is below for offline reading.


Changelog

All notable changes to aiscope are documented here.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Unreleased

[0.1.1] — 2026-04-27

Changed

0.1.0 — 2026-04-27

Added

  • Multi-tool discovery across Cursor, Claude Code, and GitHub Copilot, spanning all 5 subsystems: instructions, prompts, agents, chat modes, skills.
  • AGENTS.md and CLAUDE.md any-depth discovery with automatic path-derived scope (e.g. apps/web/AGENTS.mdapps/web/**).
  • Frontmatter-aware parser for applyTo, globs, alwaysApply, tools:, model:, name:, description:.
  • Scope overlap detection via globset — non-overlapping rules are demoted to Low severity instead of false-positive HIGH conflicts.
  • Two reasoning modes: --specific (subsystem-aware) and Uniform (default).
  • Agent tool-allowlist mismatch detector — flags when an instruction says "use the X tool" but the agent's tools: excludes X.
  • Duplicate-name detection across agents, skills, and chat modes.
  • 5 renderers: ratatui TUI, miette compiler-style diagnostics, plain text, JSON, and a 1280×720 PNG summary card with embedded JetBrains Mono.
  • CI gate: aiscope check exits non-zero on HIGH conflicts.
  • Privacy guard: never reads outside the repo unless --user is passed; never reads Claude Code transcript history under ~/.claude/projects/.

Quality

  • 42 tests passing (33 unit + 5 corpus snapshots + 2 copilot-only integration
    • 1 smoke + 1 privacy guard).
  • cargo clippy --all-targets -- -D warnings clean.
  • ~5 MB release binary.

Contributing

Full guide: CONTRIBUTING.md.

TL;DR

git clone https://github.com/Jayanth-MKV/aiscope
cd aiscope
cargo test
cargo clippy --all-targets -- -D warnings
cargo fmt --check

Then open a PR. See CONTRIBUTING.md for the full development loop, the test fixture layout, and the bar for landing changes.

Code of Conduct

This project follows the Contributor Covenant 2.1.

Reporting security issues

See SECURITY.md. Do not open a public issue for security reports.