Configure Windsurf Rules for AI Agent Project Context 2026

Set up Windsurf Rules to give AI agents persistent project context, coding standards, and memory. Works with .windsurfrules and global rules. TypeScript & Python tested.

Problem: Windsurf Forgets Your Project Standards Every Session

Windsurf Rules project context lets you encode your architecture decisions, coding conventions, and repo structure once — so the AI agent stops asking the same questions and stops suggesting patterns that don't fit your stack.

Without rules, Cascade rewrites your Zod schemas in a style you don't use, picks the wrong test runner, and ignores your monorepo boundaries. You end up re-explaining your stack on every task.

You'll learn:

  • How to write a .windsurfrules file that gives Cascade accurate project memory
  • How global rules and workspace rules interact — and which wins
  • Three rule templates for TypeScript monorepos, Python FastAPI projects, and full-stack Next.js apps

Time: 15 min | Difficulty: Intermediate


Why This Happens

Cascade is a stateless agent. It has no persistent memory of your project between sessions unless you give it an explicit context file. Each new task starts from scratch.

.windsurfrules is the mechanism Windsurf provides to inject always-on context into every Cascade prompt. Think of it as a system prompt that's scoped to your workspace.

Symptoms you're missing rules:

  • Cascade suggests axios when your project uses fetch + ky
  • It generates class components in a hooks-only React codebase
  • It creates new files outside your src/ structure
  • It adds console.log debug statements in production code paths
  • It picks unittest in a project that's standardized on pytest

How Windsurf Rules Work

Windsurf loads rules from two locations at startup:

LayerFileScope
Global~/.codeium/windsurf/global_rules.mdAll workspaces
Workspace.windsurfrules at repo rootCurrent project only

Both files are injected into Cascade's context on every turn. Workspace rules are appended after global rules — meaning workspace rules take precedence when they conflict.

There is a 6,000 token limit across both files combined. Budget global rules for universal preferences (language, formatting) and workspace rules for project-specific architecture.


Solution

Step 1: Create the Workspace Rules File

At your repo root, create .windsurfrules:

touch .windsurfrules

Then open it in Windsurf. Cascade can read and edit this file like any other — you can ask it to update its own rules as the project evolves.

Commit this file to version control. Every developer on the team shares the same agent behavior.


Step 2: Write Your Project Context Block

Start with a project summary section. This is the single highest-value block — it orients Cascade before any task.

# Project Context

## Stack
- Runtime: Node 22 + TypeScript 5.4 (strict mode)
- Framework: Next.js 15 App Router — no Pages Router
- Styling: Tailwind CSS 4 + shadcn/ui — no CSS modules, no styled-components
- State: Zustand for client state, React Query v5 for server state
- Auth: Clerk — never roll custom auth
- DB: PostgreSQL 16 via Drizzle ORM — no raw SQL unless in a migration file
- Testing: Vitest + Playwright — no Jest, no Cypress
- Package manager: pnpm — never suggest npm or yarn commands

## Monorepo Structure
apps/
  web/       # Next.js frontend
  api/       # Hono API on Bun
packages/
  db/        # Drizzle schema + migrations
  ui/        # shadcn component library
  config/    # Shared ESLint, TypeScript, Tailwind configs

Why this matters: Cascade checks this block before suggesting imports. A package manager line alone saves 10+ correction cycles per week on a shared codebase.


Step 3: Add Coding Standards

Separate standards from context. Keep them scannable.

## Coding Standards

### TypeScript
- Always use `type` for object shapes, `interface` only for extendable contracts
- No `any` — use `unknown` + type guard or `z.infer<typeof schema>`
- Prefer `const` arrow functions over `function` declarations in components
- Export types from `types.ts` in each package — never inline in function signatures

### File Naming
- Components: PascalCase (`UserCard.tsx`)
- Utilities: camelCase (`formatDate.ts`)
- Route handlers: lowercase (`route.ts` — Next.js convention)
- Test files: co-located, `.test.ts` suffix (`UserCard.test.tsx`)

### Error Handling
- Server actions throw `ActionError` from `@/lib/errors` — never throw raw `Error`
- API routes return `{ error: string; code: string }` on failure — never expose stack traces
- All async functions must have explicit return types

### Imports
- Use `@/` path alias for `apps/web/src/` — no relative `../../` beyond one level
- Barrel exports via `index.ts` in each package — import from package, not deep path

Step 4: Add Agent Behavior Rules

This section tells Cascade how to work, not just what the project looks like.

## Agent Behavior

### Before writing code
- State what you're about to change and why — one sentence
- If the task touches the DB schema, confirm the migration strategy before writing

### File creation
- Never create files outside the existing directory structure without asking
- If a utility already exists in `packages/`, use it — do not duplicate

### Code style
- No `console.log` in production paths — use the logger at `@/lib/logger`
- No TODO comments unless the task explicitly asks to leave one
- Match the surrounding code style — if existing code uses early returns, use early returns

### Testing
- Every new exported function gets a Vitest unit test
- Every new route gets a Playwright API test in `tests/api/`
- Do not modify existing tests to make new code pass — fix the code

### Commits
- Use conventional commits: `feat:`, `fix:`, `chore:`, `refactor:`
- Scope to the package: `feat(web):`, `fix(api):`

Step 5: Configure Global Rules for Universal Preferences

Edit ~/.codeium/windsurf/global_rules.md for preferences that apply across all your projects:

mkdir -p ~/.codeium/windsurf
nano ~/.codeium/windsurf/global_rules.md
# Global Rules

## Language
- Respond in English
- Be direct — no preamble, no "Great question!", no "Certainly!"
- When uncertain, say so and give the two most likely options

## Code output
- Show diffs when editing existing files, not full file rewrites
- Add a one-line comment explaining WHY for any non-obvious logic
- Prefer explicit over clever — no one-liners that sacrifice readability

## Security
- Never hardcode secrets, API keys, or credentials
- Always flag if a suggested change touches auth, permissions, or data access

Expected result: Open any workspace — Cascade now applies these preferences automatically.


Step 6: Verify Rules Are Loading

Open Windsurf, start a new Cascade task, and ask:

What rules are you operating under for this project?

Cascade will summarize the rules it has loaded. If it can't describe your stack accurately, the file has a syntax issue or is in the wrong location.

Confirm the file is at the repo root:

ls -la .windsurfrules
# -rw-r--r--  1 user  staff  2847 Mar 11 09:00 .windsurfrules

Rule Templates

Template: Python FastAPI Project

# Project Context

## Stack
- Python 3.12 + uv for package management — no pip, no poetry
- Framework: FastAPI 0.115 — no Flask, no Django
- Validation: Pydantic v2 — always use `model_validator` not `validator`
- DB: PostgreSQL via SQLAlchemy 2.0 async — no sync sessions in route handlers
- Testing: pytest + httpx AsyncClient — no unittest
- Linting: Ruff — no flake8, no black (Ruff handles formatting too)

## Project Structure
src/
  api/        # FastAPI routers
  models/     # SQLAlchemy ORM models
  schemas/    # Pydantic request/response schemas
  services/   # Business logic — no DB calls in routers
  core/       # Config, DB session, dependencies

## Standards
- Services own DB logic — routers call services, never query directly
- All endpoints are async — no sync def route handlers
- Dependency injection via `Depends()` for auth and DB sessions
- Return types always explicit on route handlers

Template: TypeScript Monorepo (Turborepo)

# Project Context

## Stack
- Node 22 + TypeScript 5.4 strict
- Build: Turborepo with pnpm workspaces
- API: Hono on Bun runtime — no Express
- Frontend: SvelteKit 2 — no React in this project
- DB: Drizzle ORM + PlanetScale (MySQL 8 compatible)
- Testing: Vitest across all packages

## Turborepo Pipeline
- `turbo build` — transpile all packages before apps
- `turbo test` — run affected tests only (--filter flag)
- Never run `tsc` directly — always `turbo typecheck`

## Shared Packages
packages/db — Drizzle schema, migrations, seed scripts
packages/utils — Pure functions, no framework deps
packages/env — t3-env schema for type-safe environment variables

Verification

After setting up your rules, run this Cascade prompt on a real task:

Create a new user profile endpoint. Follow project conventions.

You should see:

  • Correct file placed in your router directory (not invented location)
  • Correct ORM / DB pattern from your rules
  • No package manager mismatch
  • Test file created alongside the feature file

If Cascade deviates, add a more specific rule to the failing section. Rules improve iteratively — treat them like code.


What You Learned

  • .windsurfrules at repo root is workspace-scoped; global_rules.md is user-scoped — workspace wins on conflicts
  • The 6,000 token budget forces you to prioritize: architecture decisions over style nitpicks
  • Committing .windsurfrules to version control standardizes AI behavior across the entire team
  • Agent behavior rules (how to work) are as important as project context rules (what the project is)

Tested on Windsurf 1.9, macOS Sequoia 15.3 & Ubuntu 24.04


FAQ

Q: Does .windsurfrules work with Windsurf's offline/local model mode? A: Yes. Rules are injected at the prompt level before any model call — they work with both cloud and local model backends.

Q: What happens if my rules exceed the 6,000 token limit? A: Windsurf silently truncates from the bottom. Put your highest-priority context at the top of each file, and check token count with a tokenizer like tiktoken if your file is large.

Q: Can I have per-directory rules in a monorepo? A: Not natively. One .windsurfrules per repo root. Work around this by structuring your rules with explicit section headers per app/package and telling Cascade which section applies.

Q: How is this different from Cursor's .cursorrules? A: The file format is similar — both inject into system context. Windsurf's Cascade has deeper flow awareness (it can plan multi-file edits before starting), so rules about file creation and dependency boundaries have more effect than in Cursor's single-turn Composer.

Q: Should I add .windsurfrules to .gitignore? A: No — commit it. The whole value is that every developer and every CI session runs Cascade with the same project context. Only add it to .gitignore if the file contains secrets, which it should never do.