Prompting & Context Compared
Same prompt. Three tools. Wildly different results. This module dissects exactly how Claude Code, Gemini CLI, and GitHub Copilot CLI interpret context — from project-level instruction files to per-call file references — and shows you how to prompt each one for maximum value.
Context Files: CLAUDE.md vs GEMINI.md vs copilot-instructions.md
BEFORE: You join a new team and on day one you're asked to fix a bug. You don't know the coding conventions, which dependencies are banned, which API version to use, or that "never commit .env files" is a cardinal rule. You make 4 mistakes before lunch that every senior dev considers obvious. The problem isn't your skills — it's missing context.
PAIN: Without a persistent briefing document, every new AI session starts cold. You re-explain the stack, the constraints, and the team preferences — over and over — costing minutes per session, which adds up to hours per week. The AI gives generic advice because it has no project-specific knowledge.
MAPPING: A context file is the onboarding document you hand your AI assistant on session zero, and it stays in effect for every subsequent conversation. Instead of repeating "we use Pydantic v2, not v1" forty times, you write it once in CLAUDE.md and forget about it.
The side-by-side reveals the pattern: CLAUDE.md and GEMINI.md are nearly identical — the stack, rules, and run commands are copy-paste portable. Only the last section changes to swap out tool-specific hints. copilot-instructions.md is much simpler because the CLI tool doesn't load it, and the IDE version has a more limited scope.
| Feature | CLAUDE.md | GEMINI.md | copilot-instructions.md |
|---|---|---|---|
| Loaded in terminal | ✓ Yes | ✓ Yes | ✗ IDE/PR only |
| Global scope (~/ home) | ✓ ~/.claude/ | ✓ ~/.gemini/ | ✗ Project only |
| Model hints | ✓ Supported | ✓ Supported | ✗ Not supported |
| Slash command / skill definitions | ✓ Slash cmds | ✓ Skills | ✗ Not supported |
| Cross-session memory | ✓ Always loaded | ✓ /memory add | ✗ N/A (stateless CLI) |
| Transferability | Copy → rename to GEMINI.md, swap last section | Copy → rename to CLAUDE.md, swap last section | Rewrite needed (different scope) |
Many teams create a single project-context.md with shared content and use a build step or simple shell alias to generate both CLAUDE.md and GEMINI.md. When you update the shared doc, both tools get the update automatically.
@ Context Syntax Compared
All three tools can reference specific files in your prompt — but the mechanism is different for each. This is one of the most practically important differences for day-to-day use.
/add in interactive mode to pin files.
@ prefix for files, directories, and URLs. Most powerful: can load an entire directory or a live API spec with one token.
cat — not an AI analysis.
# ── CLAUDE CODE ──────────────────────────────────────────────
# No @ syntax — describe files naturally in your prompt
claude "Look at src/auth.js and explain the session management"
# In interactive mode, pin a file so Claude always reads it:
# /add src/auth.js
# Claude will then reference it in every subsequent response.
# ── GEMINI CLI ───────────────────────────────────────────────
# @ prefix for a single file
gemini "@src/auth.js explain the session management"
# @ prefix for an entire directory (uses 1M context window)
gemini "@src/ summarize every module and its responsibilities"
# @ prefix for a live URL — loads an API spec and generates client code
gemini "@https://api.stripe.com/openapi.json generate a Python client"
# Combine multiple @ references in one prompt
gemini "@src/auth.js @tests/auth.test.js what's not covered by tests?"
# ── GITHUB COPILOT CLI ───────────────────────────────────────
# No file @ syntax — translates requests to shell commands
gh copilot suggest "show the content of src/auth.js and summarize it"
# Result: suggests `cat src/auth.js` — not an AI analysis of the file
# ── CLAUDE CODE ──────────────────────────────────────────────
# No @ syntax — describe files naturally in your prompt
claude "Look at src/auth.js and explain the session management"
# In interactive mode, pin a file:
# /add src/auth.js
# ── GEMINI CLI ───────────────────────────────────────────────
# @ prefix for a single file
gemini "@src/auth.js explain the session management"
# @ prefix for a directory
gemini "@src/ summarize every module and its responsibilities"
# @ prefix for a live URL
gemini "@https://api.stripe.com/openapi.json generate a Python client"
# Combine multiple @ references
gemini "@src/auth.js @tests/auth.test.js what's not covered by tests?"
# ── GITHUB COPILOT CLI ───────────────────────────────────────
# Copilot CLI translates to shell commands, not file analysis
gh copilot suggest "show the content of src/auth.js and summarize it"
# Suggests: Get-Content src/auth.js — not an AI analysis
The Same Prompt, Three Tools
The clearest way to understand the behavioral difference between these tools is to run the exact same prompt on all three and compare output style, depth, and approach. Here's the test prompt:
"Explain what this codebase does, identify the main entry point,
and list the top 3 things a new developer should understand first."
main.py — FastAPI app, mounts all routers, loads config from settings.py.
Top 3 for new devs:1. Webhooks use idempotency keys — re-processing is intentional.
2. Plan changes are async — don't expect synchronous DB updates.
3.
.env.example shows all required secrets before first run.
Note: I didn't find test coverage for the webhook retry logic — worth asking about.
main.py (API server), worker/index.ts (webhook processor).
Top 3:1. Dual-language codebase — API in Python, worker in TypeScript.
2. Alembic migrations are the source of truth for DB schema.
3. Stripe webhook signatures validated in
webhooks/verify.py.
I read all 47 source files in one pass. Want a full dependency map?
cat README.md — read the overview
find . -name "*.py" | head -20 — list Python files
grep -r "if __name__" . --include="*.py" — find entry points
Copilot CLI translates your prompt into shell commands — it doesn't analyze the codebase itself. Use it to discover the right commands, then read the output yourself.
All three tools responded usefully — but to very different kinds of usefulness. Notice:
- Claude Code reads specific files, explains architecture in prose, and proactively flags gaps (the missing test coverage).
- Gemini CLI loads the entire codebase at once (its 1M window advantage), identifies both entry points (including the TypeScript worker), and offers to go deeper.
- Copilot CLI doesn't analyze — it suggests the shell commands you would use to analyze. That's its design. It's genuinely useful if you forgot the right
grepsyntax.
Multi-Turn Conversation Patterns
How each tool handles memory and context across multiple messages is one of the most consequential differences for long-running tasks. A tool that forgets context after each message forces you to re-explain everything — just like repeating yourself to a new colleague every morning.
# ── CLAUDE CODE ──────────────────────────────────────────────
# Session context is maintained automatically.
# Subagent example: parallel tasks within one session
claude "Write the implementation of the payment retry logic
AND write tests for it at the same time."
# Claude spins up a subagent for tests, main agent for impl,
# both report back — you see both files when done.
# Reset session when starting a new task:
# /clear
# CLAUDE.md is still loaded — only the conversation resets.
# ── GEMINI CLI ───────────────────────────────────────────────
# Save a named session to resume later
gemini
# (interactive mode)
# > Analyze the payment service architecture
# > /chat save payment-analysis
# Next day — resume exactly where you left off
gemini
# > /chat resume payment-analysis
# > Now add the retry logic we discussed
# Add a persistent memory note (survives session restarts)
# > /memory add "This project uses pydantic v2 exclusively"
# ── GITHUB COPILOT CLI ───────────────────────────────────────
# Each call is completely stateless
gh copilot suggest "list files in src directory"
# Returns: ls src/ or Get-ChildItem src/
# Next call has NO memory of the previous one
gh copilot suggest "now show me the auth module"
# Returns: cat src/auth.js (no "now" context — clean slate)
# ── CLAUDE CODE ──────────────────────────────────────────────
# Session context maintained automatically (200K token window).
# Subagent example: spawn parallel tasks
claude "Write the payment retry implementation AND its tests simultaneously."
# A subagent handles tests; main agent handles implementation.
# Both results appear in session context when complete.
# Reset session (CLAUDE.md still loaded after /clear):
# /clear
# ── GEMINI CLI ───────────────────────────────────────────────
# Interactive session with named-session save/resume
gemini
# In interactive mode:
# > Analyze the payment service architecture
# > /chat save payment-analysis
# Resume the named session in a new terminal session
gemini
# > /chat resume payment-analysis
# > Now add the retry logic we discussed
# Persistent memory across all sessions
# > /memory add "This project uses pydantic v2 exclusively"
# ── GITHUB COPILOT CLI ───────────────────────────────────────
# Stateless — every gh copilot suggest is a fresh start
gh copilot suggest "list files in src directory"
# Output: Get-ChildItem src\
# No context from previous call
gh copilot suggest "now show me the auth module"
# Output: Get-Content src\auth.js (ignores "now" — no history)
Both maintain full multi-turn context. Claude Code's subagents are powerful for parallel work. Gemini's /chat save / /chat resume and /memory add are great for cross-day continuity. Use stateless Copilot CLI for quick, one-off lookups only.
Tool-Specific Prompt Tips
Generic prompting advice ("be specific," "give examples") applies everywhere. But each tool has behaviors and strengths that reward particular prompting patterns — and ignoring those patterns leaves significant quality on the table.
- Be specific about what should change vs what should stay the same — prevents unintended rewrites
- "Explain your reasoning before writing code" — forces step-by-step thinking and catches wrong approaches early
- Use CLAUDE.md to set default coding standards — never repeat conventions in prompts
- Ask it to write tests before the implementation — locks in expected behavior first
- "What's the simplest change that achieves X?" — prevents over-engineering
- For risky changes: "what could go wrong with this approach?" before committing
- Use
@aggressively — more context = better results with the 1M window /memory addyour preferences once; they persist so you never repeat them- Start with
/planfor complex tasks — review the approach before execution begins - Use
--model gemini-2.5-profor architecture decisions;flashfor quick lookups - Load an entire directory:
@src/ what's the overall architecture?— the full picture matters /chat savebefore ending a long session; resume tomorrow with full context
- It excels at shell command translation — lean into that, don't fight it
gh copilot explain <command>is excellent for understanding unfamiliar commands- Combine with IDE Copilot for a full workflow: CLI for shell tasks, IDE for code analysis
- Specify command type:
-t shellvs-t gitvs-t ghfor tighter results - Paste complete error messages — it suggests the right debugging command sequence
- Use for GitHub Actions syntax lookups — it knows YAML workflow structure well
# ── CLAUDE CODE: reasoning before code ───────────────────────
claude "Explain your reasoning about the best approach, then write
the retry middleware for the Stripe webhook handler.
Keep the existing error logging pattern unchanged."
# ── CLAUDE CODE: tests first ──────────────────────────────────
claude "Write tests for the payment retry logic BEFORE writing the
implementation. Make the tests fail first, then fix them."
# ── GEMINI CLI: aggressive @ loading ─────────────────────────
gemini "@src/payments/ @src/webhooks/ @migrations/ \
What's missing from our error-handling strategy?"
# ── GEMINI CLI: /plan before executing ───────────────────────
gemini
# > /plan refactor the payment module to add idempotency keys
# Review the plan, ask questions, THEN approve execution
# ── GEMINI CLI: model selection ──────────────────────────────
gemini --model gemini-2.5-pro \
"@src/ Design the retry architecture for webhook failures"
gemini --model gemini-2.5-flash \
"What flag does grep use for case-insensitive search?"
# ── COPILOT CLI: command-type flag ────────────────────────────
gh copilot suggest -t git "undo last commit but keep changes staged"
gh copilot suggest -t gh "create a PR from current branch to main"
gh copilot suggest -t shell "find all .env files recursively"
# ── COPILOT CLI: explain a command ───────────────────────────
gh copilot explain "git rebase -i HEAD~3"
# ── CLAUDE CODE: reasoning before code ───────────────────────
claude "Explain your reasoning about the best approach, then write
the retry middleware for the Stripe webhook handler.
Keep the existing error logging pattern unchanged."
# ── CLAUDE CODE: tests first ──────────────────────────────────
claude "Write tests for the payment retry logic BEFORE writing the
implementation. Make the tests fail first, then fix them."
# ── GEMINI CLI: aggressive @ loading ─────────────────────────
gemini "@src/payments/ @src/webhooks/ @migrations/ What's missing from our error-handling strategy?"
# ── GEMINI CLI: /plan before executing ───────────────────────
# In interactive Gemini session:
# > /plan refactor the payment module to add idempotency keys
# Review plan, then approve
# ── GEMINI CLI: model selection ──────────────────────────────
gemini --model gemini-2.5-pro "@src/ Design the retry architecture for webhook failures"
gemini --model gemini-2.5-flash "What flag does Select-String use for case-insensitive search?"
# ── COPILOT CLI: command-type flag ────────────────────────────
gh copilot suggest -t git "undo last commit but keep changes staged"
gh copilot suggest -t gh "create a PR from current branch to main"
gh copilot suggest -t shell "find all .env files recursively"
# ── COPILOT CLI: explain a command ───────────────────────────
gh copilot explain "git rebase -i HEAD~3"
Error Handling Prompts
Pasting an error message is one of the most common real-world prompts you'll use. Each tool handles it through the lens of its core philosophy — analysis, code fix, or shell debugging command.
TypeError: Cannot read properties of undefined (reading 'map')
at processWebhookEvents (src/webhooks/processor.js:47:28)
at async handleStripeEvent (src/webhooks/handler.js:23:5)
processor.js:47 and handler.js:23 automatically. Asks: "Is events expected to be an array or can it be null?" Then proposes a targeted fix with a null guard and explains why it can be undefined (Stripe sometimes sends an empty payload on certain event types).
@src/webhooks/, finds the error location, and cross-references other callers of processWebhookEvents across the codebase. Suggests the fix plus a broader audit: "2 other callers also skip null-checking — want me to fix those too?"
node --stack-trace-limit=20 src/webhooks/handler.js and grep -n "map" src/webhooks/processor.js. Useful for finding the exact line fast — but the actual debugging is left to you.
Copilot CLI is excellent at "what command do I run to see this error?" but it won't read your source files and diagnose the root cause. For error diagnosis that requires reading code, Claude Code or Gemini CLI are the right tools. Use Copilot CLI to generate the debugging commands, then hand the analysis to one of the other tools.
You now have the full prompting picture for all three tools. You can answer:
- What's the structural difference between CLAUDE.md and copilot-instructions.md?
- When would you use
@src/vs natural language file references? - Why does Gemini CLI sometimes find more issues in a codebase scan than Claude Code?
- Which tool is appropriate for a long, multi-day refactoring task? Which for a 30-second shell command lookup?
- How does each tool respond differently to the same error message?
Next module (M04) covers code generation — writing new files, refactoring existing ones, and how each tool handles large, multi-file changes.
Knowledge Check
Test your understanding of prompting and context across all three tools — 6 questions.
gh copilot suggest CLI tool does NOT read it. This is a common source of confusion.
gemini "@src/ @tests/ what's not covered by our tests?". What is the @ syntax doing here?src/ and tests/ and includes their contents in the prompt before generating a response. This is what makes its 1M context window so powerful for codebase-wide analysis.
node --stack-trace-limit=20 or grep -n "map" file.js. It doesn't read your source files and diagnose root causes — that's the job of Claude Code or Gemini CLI.
/memory add command do that running gemini fresh each time does NOT?/memory add "use pydantic v2" stores that fact in Gemini's persistent memory, which is automatically included in every future session. Unlike GEMINI.md (which is project-specific), memory notes travel with your Gemini user profile. They're great for personal preferences like coding style or toolchain choices.
/chat save is a Gemini CLI feature, not Claude Code.