Context, Memory & the Codebase Index
Windsurf's context system determines what information Cascade has when generating code. Mastering it is the difference between generic AI suggestions and deeply codebase-aware outputs that match your team's exact conventions. This module covers every layer of the context system: the codebase index, @ mentions, pinned context, Memories, and the .windsurfrules file -- plus practical strategies for optimising what Cascade sees to maximise output quality.
The Context Hierarchy
Cascade assembles context from multiple sources, each with different priority and scope. Understanding this hierarchy helps you control exactly what information Cascade has when generating code:
Codebase Index
Windsurf automatically indexes your repository and updates the index as you edit. The index enables semantic search -- Cascade finds relevant code by concept, not just by filename or literal text match. This is what enables zero-shot multi-file edits.
Pinned Context
Pin specific files, functions, or selections in the Cascade panel to always be included in context. Use for core architectural files, API contracts, style guides, or any file that should inform every edit in a session.
@ Mentions
Reference specific files, functions, or symbols using @ in your prompts: "@src/api/auth.ts fix the rate limiting logic". Cascade focuses attention on the referenced item and fetches its full content regardless of what the auto-selection algorithm chose.
Memories
Cascade can persist facts about your project across sessions -- coding conventions, architectural decisions, team preferences, recurring patterns. Define memories explicitly via the Memories panel or let Cascade infer them from patterns it notices.
The priority order (highest to lowest): (1) Explicitly @ mentioned files, (2) Pinned context, (3) Memories, (4) .windsurfrules, (5) Currently open file, (6) Recently edited files, (7) Semantically relevant files from the index. When the context window is full, lower-priority items are dropped first. This means your @ mentions and pinned files are guaranteed to be in context; semantically retrieved files are best-effort.
Every LLM has a finite context window (the total amount of text it can consider at once). Windsurf manages this automatically, but you can help by being selective about what you pin and mention. Pinning your entire src/ directory is counterproductive -- it floods the context with irrelevant code, pushing out the files that actually matter. Pin only the files that should inform every edit: base classes, type definitions, configuration, and style guides.
The Codebase Index -- How It Works
When you open a project in Windsurf, the indexing engine scans every file and builds a semantic representation. This is fundamentally different from a text search index (like grep). The semantic index understands:
- Symbols: Function names, class names, variable names, types, and their definitions
- Relationships: Which functions call which other functions, which classes inherit from which base classes, which modules import which other modules
- Concepts: The semantic meaning of code blocks -- not just that a function is named "validate_email" but that it performs email validation using a regex pattern
- Patterns: Recurring coding patterns in your codebase -- how you structure tests, how you handle errors, how you define API endpoints
The index updates incrementally as you edit. You do not need to re-index manually. However, if you add a large number of files at once (e.g., pulling a major branch), the re-indexing may take a few minutes -- you will see the progress in the status bar.
What Gets Indexed (and What Does Not)
By default, Windsurf indexes all source files and ignores binary files, node_modules, build artifacts, and version control directories. You can customise this in your Windsurf settings:
{
"windsurf.index.exclude": [
"node_modules/**",
"dist/**",
"build/**",
".next/**",
"coverage/**",
"*.min.js",
"*.bundle.js",
"data/fixtures/**",
"generated/**"
],
"windsurf.index.include": [
"**/*.py",
"**/*.ts",
"**/*.tsx",
"**/*.js",
"**/*.jsx",
"**/*.yaml",
"**/*.yml",
"**/*.json",
"**/*.md"
]
}
@ Mentions -- Precision Context Control
The @ mention is your most direct tool for controlling what Cascade sees. When you type @ in a Flow or Chat prompt, Windsurf shows a searchable list of files, functions, classes, and symbols. Selecting one guarantees its full content is included in the context, regardless of what the automatic context selection algorithm chose.
When to Use @ Mentions
- When Cascade keeps getting a convention wrong: @ mention the file that demonstrates the correct convention. "Add a new endpoint following the exact pattern in @src/api/routes/products.py"
- When working on code that depends on another file: @ mention the dependency. "Fix the error in @src/services/order.py -- the OrderRepository interface is defined in @src/repositories/order_repository.py"
- When the automatic context is insufficient: If Cascade's output shows it does not know about a file it should, add an @ mention in your next prompt.
- When you want to reference a specific function, not the whole file: Use @filename:functionName to include just that function's definition.
@ Mention Syntax
| Syntax | What It Includes | Example |
|---|---|---|
| @filename | The entire file | @src/models/user.py |
| @filename:function | A specific function definition | @src/services/auth.py:validate_token |
| @filename:class | A specific class definition | @src/models/user.py:User |
| @folder/ | All files in the folder (shallow) | @src/api/routes/ |
Mentioning too many files dilutes Cascade's attention. The context window is finite -- every file you @ mention takes space away from the automatic context selection. A good rule: mention 1-4 files per prompt. If you find yourself needing to mention more than 5, consider whether pinned context or Memories would be a better solution.
Pinned Context -- Session-Long Focus
Pinned context stays in Cascade's context for the entire session. Unlike @ mentions (which apply to a single prompt), pinned files inform every interaction until you unpin them. This is ideal for:
- Architectural files: Base classes, interfaces, and abstract types that every new implementation should follow
- Configuration files: .windsurfrules, API contracts, database schema definitions
- Style guides: If your team has a coding style document, pin it
- The file you are actively working on: Pin it so every Flow and Chat interaction considers it
To pin a file, click the pin icon in the Cascade panel or right-click a file in the explorer and select "Pin to Cascade Context." You can pin up to 10 files simultaneously. The pinned files are shown in the Cascade panel with a pin icon.
Memories -- Persistent Cross-Session Context
Memories are facts about your project that Cascade remembers across sessions. When you close Windsurf and reopen it tomorrow, Memories persist. This makes Memories the right tool for information that is always true about your project:
- Architectural decisions: "We use the repository pattern for all data access"
- Tool choices: "All logging goes through structlog, never print()"
- Business rules: "Customer-facing text must never mention competitor brands"
- Team conventions: "All API responses include a request_id field for tracing"
- Infrastructure facts: "The production database is PostgreSQL 15 on AWS RDS"
Creating Memories
There are two ways to create Memories:
Explicit (recommended): Open the Memories panel (Cmd+Shift+M) and add facts directly. Each memory should be one clear, concise statement. Write memories as facts, not instructions: "All API responses include request_id" is better than "Please always include request_id in API responses."
Implicit: During a session, if Cascade notices you repeatedly correcting the same issue ("Use structlog, not logging"), it may suggest saving this as a Memory. You can approve or dismiss the suggestion.
Effective Memory Writing
Use good patterns.
Follow best practices.
Write clean code.
All database queries live in *_repository.py files. Services never query the DB directly.
Use pytest-asyncio for async test functions. Prefix async tests with "async def test_".
Error responses use the ErrorResponse Pydantic model with fields: error_code (str), message (str), details (dict|None).
Review your Memories monthly. Remove outdated facts (we migrated from MongoDB to PostgreSQL -- the MongoDB memory is now misleading). Update facts when conventions change. Memories that are wrong are worse than no memories at all, because Cascade will confidently apply the wrong convention.
The .windsurfrules File -- Project-Level Convention
The .windsurfrules file is a plaintext file in your project root that Cascade reads automatically for every interaction. Unlike Memories (which are per-developer), .windsurfrules is version-controlled and shared with the team. It is the single most impactful context tool -- a well-written .windsurfrules file transforms Cascade from "generic AI assistant" to "team member who knows our conventions."
What to Put in .windsurfrules
The file should contain rules that Cascade should follow when generating code for your project. Structure it in clear sections:
# Project: Agiaki Platform API # Stack: Python 3.12, FastAPI, SQLModel, PostgreSQL, pytest ## Coding Conventions - Use SQLModel for all ORM models, never raw SQLAlchemy - All endpoints must have Pydantic response models with explicit field types - Use dependency injection via FastAPI Depends() for all DB sessions - Never use print() -- use structlog for all logging - All functions must have Google-style docstrings ## Architecture Rules - Repository pattern: all DB queries live in *_repository.py files - Services orchestrate repositories; they never query the DB directly - Routers only call services; they never call repositories directly ## Testing - Use pytest with pytest-asyncio for async tests - Mock external services with respx; never make real HTTP calls in tests - Every new endpoint requires: happy path, validation error, auth failure ## Forbidden Patterns - Do NOT use mutable default arguments - Do NOT catch bare Exception -- always catch specific exceptions - Do NOT import from app.main in any module other than app.main itself
.windsurfrules Best Practices
- Be specific, not aspirational. "Use structlog for all logging" is enforceable. "Write clean, maintainable code" is not actionable.
- Include forbidden patterns. Cascade learns as much from "do not do X" as from "do Y." If your team has known anti-patterns, list them explicitly.
- Reference your stack explicitly. "Python 3.12, FastAPI, SQLModel" at the top prevents Cascade from suggesting Django patterns in a FastAPI project.
- Update it in retrospectives. When a PR review reveals a pattern Cascade keeps getting wrong, add it to .windsurfrules. The file is a living document.
- Keep it under 100 lines. A .windsurfrules file that is too long wastes context on low-value rules. Prioritise the rules that Cascade gets wrong most often.
The .windsurfrules file should be version-controlled and shared with your whole team. Every developer gets the same Cascade behaviour from day one. Update it whenever your conventions change -- treat it like a living document.
Context Window Optimisation
The context window is the bottleneck of every AI interaction. Here are strategies to maximise the value of every token in the window:
1. Exclude noise from the index. Generated files, build artifacts, vendored dependencies, and large data files consume index space without adding value. Configure exclusions in your Windsurf settings and .windsurfrules.
2. Use precise @ mentions over broad ones. @src/services/payment.py:process_refund is better than @src/services/payment.py if you only need Cascade to see the refund logic. Function-level mentions save context for other relevant files.
3. Unpin files when you switch tasks. If you were working on the payment module and now you are working on the search module, unpin the payment files. Stale pins waste context.
4. Write concise .windsurfrules. Every line in .windsurfrules consumes context in every interaction. Remove rules that Cascade already follows naturally (you do not need to tell it to use proper indentation).
5. Choose the right model for context sensitivity. Claude has a larger effective context window than some alternatives. For tasks that require understanding many files simultaneously, Claude is the better model choice even if it is slower.
Context Debugging -- When Cascade Gets It Wrong
If Cascade's output does not match your conventions or ignores relevant code, the issue is almost always context. Here is how to diagnose:
- Check what Cascade saw. In the Cascade panel, expand the "Context" section to see which files were included. If the relevant file is missing, add an @ mention.
- Check your .windsurfrules. If Cascade is using the wrong pattern, verify that the correct pattern is in .windsurfrules. Absence is the most common cause.
- Check your Memories. An outdated Memory can override your .windsurfrules. Review and update.
- Check the index status. If you recently added files, the index may not have caught up. Check the indexing indicator in the status bar.
- Check for conflicting rules. If .windsurfrules says "use structlog" but a pinned file uses print(), Cascade may be confused by the conflicting signals.
ShopMate -- Cascade Memories
# Add these to Windsurf Memories for the shopmate/ workspace
ShopMate is an AI-powered e-commerce assistant for ThreadCo, a sustainable T-shirt brand.
All Claude API calls use shopmate/logging/audit.py logged_create() -- never client.messages.create() directly.
All customer-facing replies use shopmate/safety/reply_guardrails.py safe_reply().
Brand configurations are in shopmate/config/brands.yaml -- never hardcode brand names.
The FastAPI entry point is shopmate/api/main.py.
Tests use pytest and respx to mock the Anthropic API -- never make real API calls in tests.
Environment variables are loaded from .env via python-dotenv.
The product catalogue is in data/catalogue.json and indexed in data/shopmate_kb/ via ChromaDB.
# Reference specific ShopMate files in Flow prompts for better results # Adding a new Claude feature: Add a product comparison feature following the same pattern as @shopmate/prompts/product_description.py and logging via @shopmate/logging/audit.py # Fixing the safety layer: The safe_reply() function in @shopmate/safety/reply_guardrails.py is blocking replies that mention "free returns" even when the store policy in @data/store_policy.txt explicitly states free returns are offered. # Adding a new brand: Add a new brand "NightOwlThreads" to @shopmate/config/brands.yaml following the exact same structure as the existing threadco entry. Then update @shopmate/multi_brand.py to handle the new brand. # Pin for all sessions touching Claude integration: Pin @shopmate/logging/audit.py and @shopmate/safety/reply_guardrails.py
ShopMate -- Complete .windsurfrules
# Project: ShopMate -- AI E-Commerce Assistant # Stack: Python 3.12, FastAPI, SQLModel, ChromaDB, pytest, respx ## Claude API Rules - All Claude API calls MUST go through shopmate/logging/audit.py logged_create() - Never use client.messages.create() directly - Always pass brand_id and feature name to logged_create() - Customer-facing replies MUST go through shopmate/safety/reply_guardrails.py safe_reply() ## Architecture - FastAPI entry point: shopmate/api/main.py - Prompt templates: shopmate/prompts/ (module-level string constants, not inline strings) - Brand config: shopmate/config/brands.yaml (never hardcode brand names or voices) - Product data: data/catalogue.json, indexed in data/shopmate_kb/ (ChromaDB) ## Coding Conventions - Google-style docstrings on all public functions - Use structlog for logging, never print() - Use Pydantic models for all API request/response schemas - Environment variables loaded from .env via python-dotenv ## Testing - pytest + respx for mocking Anthropic API calls - Never make real API calls in tests - Every new feature needs: happy path, error case, brand voice test (if multi-brand) ## Forbidden Patterns - Do NOT hardcode API keys or brand names - Do NOT catch bare Exception - Do NOT use mutable default arguments - Do NOT import from shopmate.api.main in other modules
Hands-On Exercises
Create a .windsurfrules file for a project you are currently working on. Include at least: (1) your stack/language/framework, (2) 5 coding conventions, (3) your architecture rules (where does business logic live? where do tests go?), (4) 3 forbidden patterns. Commit it to your repository. Then ask Cascade to add a small feature and see if it follows your rules. If it violates any, refine the .windsurfrules and try again.
Run the same Flow prompt twice: once without any @ mentions, and once with 2-3 targeted @ mentions for the most relevant files. Compare the output quality. Did the @ mentioned version follow your conventions more closely? Did it make fewer mistakes at file boundaries (imports, types, function signatures)?
Open the Memories panel (Cmd+Shift+M) and add 5-8 memories about your project. Include: the stack, the architecture pattern, the testing framework, the logging approach, and one business rule. Then start a new session and ask Cascade to add a feature. Did it incorporate the memories without being prompted? Check each memory against the output.
Intentionally give Cascade a task where it will need a file you have not mentioned or pinned. After it generates code, check the Context panel to see which files it auto-selected. Was the critical file included? If not, add an @ mention and rerun. This exercise builds your intuition for when automatic context is sufficient and when you need to intervene.
Review your current Windsurf setup: how many files are pinned? Are any stale? How many Memories do you have? Are any outdated? Is your .windsurfrules under 100 lines? Does your index exclude generated files? Optimise each layer based on your findings. After the audit, run a representative Flow and see if the output quality improved compared to before the audit.