Back to Portfolio HomePortfolioContext & Token Cheat-Sheet

Be Digital · Bonus material · GenAI Advisory

Context & Token Cheat-Sheet: GitHub Copilot vs Claude Code

How each tool builds context, what it ignores vs loads, and how that drives token usage.

Directory structure — what each tool cares about

Both tools need to understand your project layout, but they discover it in fundamentally different ways.

Aspect GitHub Copilot Claude Code
Discovery method Semantic index — builds a vector embedding of the workspace at startup; retrieves relevant snippets on each prompt On-demand file reads — Read tool calls triggered by the model during the conversation
What it sees first Open editor tabs + semantically similar chunks from the index CLAUDE.md (project memory) + whatever the model decides to read
Tree awareness Implicit — the index covers all non-ignored files; no explicit tree walk Explicit — model calls ListDir or Glob to navigate the repo tree
Config that controls scope .copilotignore, VS Code files.exclude .claude/settings.json deny rules (block reads/writes by path pattern)

Claude Code tree example — what a typical exploration looks like in the conversation log:

# Claude Code navigates a regulated Java codebase
ListDir → /
├── CLAUDE.md
├── .claude/
│   ├── settings.json
│   └── commands/
├── src/
│   ├── main/java/com/app/   ← denied by settings.json
│   └── test/java/com/app/   ← allowed — write target
├── pom.xml                   ← denied (frozen)
└── target/site/jacoco/       ← read-only, coverage data

Read → target/site/jacoco/jacoco.xml
Read → src/main/java/com/app/PriceService.java
Write → src/test/java/com/app/PriceServiceTest.java
How each tool builds context GitHub Copilot Workspace files Semantic index (vector embeddings) Retrieval → relevant snippets Context window Claude Code CLAUDE.md (always loaded) Model decides what to read On-demand Read / ListDir / Glob Context window

What's IGNORED vs LOADED

GitHub Copilot

Ignored:

  • Files matching .copilotignore patterns (same syntax as .gitignore)
  • Files excluded by VS Code files.exclude / search.exclude
  • Binary files, images, compiled output
  • node_modules/, .git/, build artifacts by default

Loaded:

  • Currently open editor tabs (highest priority)
  • Semantically similar chunks from the workspace index
  • .github/copilot-instructions.md — always injected as system context
  • *.instructions.md files scoped to specific directories/patterns
  • Prompt files (.github/prompts/*.prompt.md) when explicitly invoked
  • Project-level skills from .github/skills/, .claude/skills/, or .agents/skills/ — Copilot reads these when committed to the repo (as of April 2026)
  • CLAUDE.md if present in the repo — Copilot reads it as project context alongside copilot-instructions.md

Key insight: Copilot's context is bounded by the retrieval window. You don't control exactly which snippets it picks — you control what's in the index by using .copilotignore and what's always present via instructions files. As of April 2026, Copilot also reads project-level skills and CLAUDE.md if committed to the repo — making these files effectively cross-tool.

Claude Code

Ignored (via deny rules):

  • Paths matching deny patterns in .claude/settings.json — blocks Read, Edit, Write tool calls
  • The model physically cannot read or write denied paths — it's an enforcement layer, not a hint
  • Typical deny targets: src/main/**, pom.xml, .env, secrets, large binaries

Loaded:

  • CLAUDE.md at project root — always loaded at session start (project memory)
  • Directory-scoped CLAUDE.md files — loaded when the model enters that directory
  • Whatever the model explicitly reads via Read tool calls
  • Slash command output (.claude/commands/*.md) when invoked
  • Conversation history (grows every turn — the main cost driver)

Key insight: Claude Code's context is explicit and observable. Every file that enters the context window was either declared (CLAUDE.md) or requested (Read tool call). You can see the full context with /context or /cost.

Token usage — the levers

Every turn in an agentic conversation re-sends the full history plus any new context. These are the levers that control how fast the meter runs.

Lever GitHub Copilot Claude Code
Always-on context copilot-instructions.md — keep it lean; it's injected every turn CLAUDE.md — same principle; every byte is re-sent on every message
Load-on-demand Prompt files (*.prompt.md) — only loaded when you invoke them Slash commands + explicit Read calls — model loads files as needed
Scope exclusion .copilotignore — removes files from the semantic index entirely Deny rules in .claude/settings.json — blocks tool calls to those paths
Conversation length Less visible — Copilot manages context window internally, auto-truncates Fully visible — use /cost to see token count; use /compact to summarize and reset
Output tokens Controlled by prompt design — shorter prompts, shorter completions Tool output counts — use maxTokens on Read calls; keep responses concise in CLAUDE.md instructions

Rules of thumb:

• Keep always-on context under ~200 lines. Claude Code's documented guidance is CLAUDE.md under 200 lines — that's the budget where the model reliably follows every rule.

• Move reference material into load-on-demand files (prompt files / slash commands).

• Exclude large generated files (coverage reports, lock files, compiled output) from indexing / context.

• In Claude Code, run /compact after major milestones to reset the conversation length without losing progress.

Quick mental model

The two tools use different names for the same concepts. Here's the mapping:

copilot-instructions.md  ↔  CLAUDE.md  (Copilot reads both if present)

*.instructions.md (directory-scoped)  ↔  directory CLAUDE.md

prompt files (.github/prompts/*.prompt.md)  ↔  Skills (.claude/skills/, .github/skills/)  — cross-tool since April 2026

Mental model — config file equivalences copilot-instructions.md CLAUDE.md *.instructions.md (scoped) directory CLAUDE.md prompt files (*.prompt.md) Skills (.claude/skills/ — cross-tool)

Bonus — filling the gaps

Hard token numbers & the /context command

Claude Code exposes its context state directly. Use these commands mid-session to understand where tokens are going:

  • /cost — shows total input/output tokens and estimated cost for the current session
  • /context — shows what's currently loaded in the context window (CLAUDE.md, conversation, read files)
  • /compact — summarizes the conversation so far and starts a fresh context with the summary, dramatically cutting token usage on the next turn
  • /clear — fully resets the session (loses all context)

Rule of thumb: Run /cost every 10–15 turns. If you're above $2 on a single session, consider /compact before continuing. The cost is cumulative — every subsequent turn re-sends everything before it.

GitHub Copilot doesn't expose equivalent commands. Token usage is managed internally by the service — you can't inspect or reset it. The lever you have is controlling what enters the index (.copilotignore) and what's always injected (instructions files).

Ignore-files — a Copilot/VS Code concept, not a Claude Code one

A common point of confusion: .copilotignore and .gitignore-style exclusion patterns are a GitHub Copilot and VS Code concept. Claude Code does not use ignore files.

In Claude Code, scope control is handled by deny rules in .claude/settings.json. These are not "ignore" hints — they are hard enforcement. A denied path cannot be read or written by the model, period. The model receives an error if it tries.

Concept GitHub Copilot Claude Code
Exclude from context .copilotignore (advisory — removes from index) Deny rules in .claude/settings.json (hard block)
Enforcement level Index exclusion — the model simply won't see the file in retrieval results Tool-call rejection — the model sees an error if it attempts access
Bypass risk Low (file not in index) but if file is open in editor, still visible None — deny rules evaluate before allow rules and cannot be overridden at project level

Sources

Addendum: Coverage Uplift Initiative — 67% → 91%

Team plan and working procedure — a test coverage sprint with credit discipline baked in.

1. Objective

Raise SonarQube line coverage from the current 67% baseline to the 91% gate, on a regulated codebase, under two hard constraints:

  • No changes to build/dependency configuration files
  • No edits to production source — test code only

Alongside the coverage target, the team will run a parallel discipline for managing coding-assistant credit spend, so the sprint doesn't trade a coverage win for an uncontrolled tooling bill.

2. Guardrail Architecture (Phase 0)

Set up once, before any test-writing begins:

  • A short, hard-rule instructions file (no build-config edits, no production-source edits) — kept minimal so it doesn't load into every session at full weight
  • Deny-rules at the tool/settings level to block edits outside the test directory
  • A pre-commit / pre-tool hook that rejects any diff touching excluded paths
  • A CI diff gate plus mutation testing to confirm new tests are meaningful, not just coverage padding
  • Detailed test-pattern examples and conventions live in a separate reference doc that loads on demand — not kept always-on in every session

3. Execution Plan (Phase 1 & 2)

3.1 Plan first, execute second

  • Build a module-by-module gap list: target class → current % → gap → test types needed
  • Review and tighten that plan manually before any test generation starts — this is the cheapest point to catch scope creep
  • Work one module per session; don't run the whole initiative in a single long-lived chat

3.2 Per-module loop

  • Open a fresh session, load only the target class and its existing test file
  • Generate tests against the approved plan slice for that module only
  • Run coverage and mutation testing locally; capture the delta
  • Compact or close the session once it runs long, rather than letting context balloon
  • Move to the next module in a new session

4. Credit Discipline

Six levers to control spend during the sprint, mapped to this initiative:

LeverRule for this initiative
InstructionsHard rules only in the always-loaded file; examples and patterns in an on-demand reference
Chat hygieneOne module per chat; compact or start fresh rather than letting sessions run long
Tools enabledOnly test-runner and coverage tools active; leave unrelated integrations off
Files in contextLoad target class + its test file only — avoid opening generated or build artifacts
Reasoning depthDefault depth for routine test-writing; increase only for genuinely tricky mutation-test gaps
Model tierPlan with a stronger model once; execute test-writing with a lighter model; escalate only after repeated rework on the same module

Track daily credit usage alongside coverage %, so the team sees cost-per-percentage-point rather than total spend in isolation. Review weekly for any module consuming disproportionate credits relative to its coverage gain — that's usually a signal the plan for that module needs to be re-scoped, not that it needs a bigger model.

5. Weekly Cadence

  • Monday: confirm the module list and plan slices for the week
  • Daily: one module cycle per contributor, tracked against the gap list
  • Friday: report coverage delta + credit spend delta together; flag any module that ran over on either axis

6. Definition of Done

  • SonarQube line coverage ≥ 91% on the target codebase
  • Zero changes to build/dependency configuration files
  • Zero changes to production source
  • Mutation testing pass rate meets the agreed threshold (not just line coverage)
  • Weekly credit spend within the agreed budget band

Failing to plan is planning to fail.

Addendum: Turning the lens on my own toolkit

I wrote last week that a control has two scores — what it catches, and what it costs the work that was never in scope. Fair to run my own coverage guardrail profile through that same test.

The short version: it holds up, and for a reason worth naming. Every enforcement layer in the profile is a file-path predicate — a diff either touches src/test/** or it doesn't. There's no semantic judgment call anywhere in the chain, which means there's no classifier to miscalibrate. The pre-commit hook and the CI guardrail stage can't have a bad week the way a safety classifier can.

One rule broke the pattern

"No coverage theater" — tests that inflate the line-coverage number without asserting real behavior — lived only in copilot-instructions.md. Discipline, not enforcement. Every other rule in that file had a CI predicate behind it; this one had a sentence.

Closed it with a mutation-score gate: PIT, scoped to whatever test classes changed on the MR, no pom.xml edits, same command-line-goal pattern already used for JaCoCo. Survived mutants on touched classes fail the pipeline. A test that passes coverage but doesn't actually pin down behavior now shows up as a number, not a hope.

Two decisions worth stating out loud

Because they're the same ones from last week's post, just smaller:

  • Scoped, not blanket. The gate runs against changed test classes, not the whole module. A repo-wide mutation threshold on day one fails the build for reasons that have nothing to do with the MR in front of you — that's the "always fires" failure mode in miniature.
  • allow_failure: true to start. The gate ships informational before it ships blocking. A threshold nobody has calibrated against real test suites yet is a guess wearing a gate's clothes. Ratchet it once you've watched it run.

Precision was the whole job last week. Turns out it's also the job when the toolkit being graded is your own.

Want this kind of work for your team?

Context engineering and token optimization for your agentic AI workflows — scoped to your tools and compliance framework.

See GenAI & AppSec advisory